def cmd_load(self, subcontext, page=None): if page is None: page = self.page context = page + ':' + subcontext state = self.macro.get_tracform_state(context) for name, value in json.loads(state or '{}').iteritems(): self.env[context + ':' + name] = value if self.subcontext is not None: self.env[self.subcontext + ':' + name] = value
def process_request(self, req): req.perm.require('FORM_EDIT_VAL') try: self.log.debug('UPDATE ARGS:' + str(req.args)) args = dict(req.args) backpath = args.pop('__backpath__', None) context = json.loads( unquote_plus(args.pop('__context__', '[null, null, null]'))) if None in context: # TRANSLATOR: HTTP error message raise HTTPBadRequest(_("__context__ is required")) basever = args.pop('__basever__', None) keep_history = args.pop('__keep_history__', None) track_fields = args.pop('__track_fields__', None) args.pop('__FORM_TOKEN', None) # Ignore. # wipe not JSON serializable arguments rejargs = [] for key, value in args.iteritems(): try: len(value) except AttributeError: rejargs.append(key) pass for key in rejargs: args.pop(key) who = req.authname result = json.dumps(args, separators=(',', ':')) self.save_tracform(context, result, who, basever, keep_history=keep_history, track_fields=track_fields) buffer = 'OK' if backpath is not None: req.send_response(302) req.send_header('Content-Type', 'text/plain') req.send_header('Location', backpath) req.send_header('Content-Length', str(len(buffer))) req.end_headers() req.write(buffer) else: req.send_response(200) req.send_header('Content-Type', 'text/plain') req.send_header('Content-Length', str(len(buffer))) req.end_headers() req.write(buffer) except Exception, e: buffer = str(e) req.send_response(500) req.send_header('Content-type', 'text/plain') req.send_header('Content-Length', str(len(buffer))) req.end_headers() req.write(buffer)
def process_request(self, req): req.perm.require('FORM_EDIT_VAL') try: self.log.debug('UPDATE ARGS:' + str(req.args)) args = dict(req.args) backpath = args.pop('__backpath__', None) context = json.loads(unquote_plus( args.pop('__context__', '[null, null, null]'))) basever = args.pop('__basever__', None) keep_history = args.pop('__keep_history__', None) track_fields = args.pop('__track_fields__', None) args.pop('__FORM_TOKEN', None) # Ignore. if context is None: # TRANSLATOR: HTTP error message raise HTTPBadRequest(_("__context__ is required")) # wipe not JSON serializable arguments rejargs = [] for key, value in args.iteritems(): try: len(value) except AttributeError: rejargs.append(key) pass for key in rejargs: args.pop(key) who = req.authname result = json.dumps(args, separators=(',', ':')) self.save_tracform(context, result, who, basever, keep_history=keep_history, track_fields=track_fields) buffer = 'OK' if backpath is not None: req.send_response(302) req.send_header('Content-Type', 'text/plain') req.send_header('Location', backpath) req.send_header('Content-Length', str(len(buffer))) req.end_headers() req.write(buffer) else: req.send_response(200) req.send_header('Content-Type', 'text/plain') req.send_header('Content-Length', str(len(buffer))) req.end_headers() req.write(buffer) except Exception, e: buffer = str(e) req.send_response(500) req.send_header('Content-type', 'text/plain') req.send_header('Content-Length', str(len(buffer))) req.end_headers() req.write(buffer)
def _request(self, path, query={}, ignore_cache=False, cache_timeout=None): MOZILLIANS_API_BASE_URL = constance.config.MOZILLIANS_API_BASE_URL MOZILLIANS_API_APPNAME = constance.config.MOZILLIANS_API_APPNAME MOZILLIANS_API_KEY = constance.config.MOZILLIANS_API_KEY MOZILLIANS_API_CACHE_KEY_PREFIX = constance.config.MOZILLIANS_API_CACHE_KEY_PREFIX MOZILLIANS_API_CACHE_TIMEOUT = constance.config.MOZILLIANS_API_CACHE_TIMEOUT endpoint = self.endpoint or MOZILLIANS_API_BASE_URL app_name = self.name or MOZILLIANS_API_APPNAME app_key = self.key or MOZILLIANS_API_KEY if cache_timeout is None: cache_timeout = MOZILLIANS_API_CACHE_TIMEOUT if not app_name or not app_key: logging.warning('Missing Mozillians app name or key') return None query['app_name'] = app_name query['app_key'] = app_key base = urlparse.urljoin(endpoint.rstrip('/') + '/', path.lstrip('/')) qs = urllib.urlencode( sorted([(key, value) for key, value in query.iteritems()])) url = '%s?%s' % ( base, qs, ) cache_key = '%s:%s' % (MOZILLIANS_API_CACHE_KEY_PREFIX, hashlib.md5(url.encode('utf-8')).hexdigest()) content = None if ignore_cache else cache.get(cache_key) if not content: try: request = urllib2.Request(url) response = urllib2.urlopen(request) content = response.read() cache.set(cache_key, content, cache_timeout) except urllib2.URLError as e: logging.error('Mozillians request failed:\n - %s\n - %s', e, url) return None try: return json.loads(content) except ValueError as e: logging.error('Parsing Mozillians response failed:\n - %s\n - %s', e, url) return None
def _postprocess(self, response): """ Makes modifications to the response object before returning it. If you don't want to throw exceptions, or parse json, override this and just return `response` """ response.raise_for_status() # For some reason, this doesn't work. #content = json.load(response) content = json.loads(response.content) if content['ok'] == '0' or content['ok'] == 0: raise GlitchError(content, response) return content
def process_request(self, req): req.perm.require('FORM_EDIT_VAL') try: self.log.debug('UPDATE ARGS:' + str(req.args)) args = dict(req.args) backpath = args.pop('__backpath__', None) context = json.loads( unquote_plus(args.pop('__context__', None)) or \ '(None, None, None)') basever = args.pop('__basever__', None) keep_history = args.pop('__keep_history__', None) track_fields = args.pop('__track_fields__', None) args.pop('__FORM_TOKEN', None) # Ignore. if context is None: # TRANSLATOR: HTTP error message raise HTTPBadRequest(_("__context__ is required")) who = req.authname result = json.dumps(args, separators=(',', ':')) self.save_tracform(context, result, who, basever, keep_history=keep_history, track_fields=track_fields) buffer = 'OK' if backpath is not None: req.send_response(302) req.send_header('Content-Type', 'text/plain') req.send_header('Location', backpath) req.send_header('Content-Length', str(len(buffer))) req.end_headers() req.write(buffer) else: req.send_response(200) req.send_header('Content-Type', 'text/plain') req.send_header('Content-Length', str(len(buffer))) req.end_headers() req.write(buffer) except Exception, e: buffer = str(e) req.send_response(500) req.send_header('Content-type', 'text/plain') req.send_header('Content-Length', str(len(buffer))) req.end_headers() req.write(buffer)
def _render_fields(self, form_id, state): fields = json.loads(state is not None and state or '{}') rendered = [] for name, value in fields.iteritems(): if value == 'on': value = _("checked (checkbox)") elif value == '': value = _("empty (text field)") else: value = '\'' + value + '\'' author, time = self.get_tracform_fieldinfo(form_id, name) rendered.append( {'name': name, 'value': value, 'author': tag.span(tag_("by %(author)s", author=author), class_='author'), 'time': time is not None and tag.span( format_datetime(time), class_='date') or None}) return rendered
def _request(self, path, query={}, ignore_cache=False, cache_timeout=None): MOZILLIANS_API_BASE_URL = constance.config.MOZILLIANS_API_BASE_URL MOZILLIANS_API_APPNAME = constance.config.MOZILLIANS_API_APPNAME MOZILLIANS_API_KEY = constance.config.MOZILLIANS_API_KEY MOZILLIANS_API_CACHE_KEY_PREFIX = constance.config.MOZILLIANS_API_CACHE_KEY_PREFIX MOZILLIANS_API_CACHE_TIMEOUT = constance.config.MOZILLIANS_API_CACHE_TIMEOUT endpoint = self.endpoint or MOZILLIANS_API_BASE_URL app_name = self.name or MOZILLIANS_API_APPNAME app_key = self.key or MOZILLIANS_API_KEY if cache_timeout is None: cache_timeout = MOZILLIANS_API_CACHE_TIMEOUT if not app_name or not app_key: logging.warning('Missing Mozillians app name or key') return None query['app_name'] = app_name query['app_key'] = app_key base = urlparse.urljoin(endpoint.rstrip('/') + '/', path.lstrip('/')) qs = urllib.urlencode(sorted([(key, value) for key, value in query.iteritems()])) url = '%s?%s' % (base, qs,) cache_key = '%s:%s' % (MOZILLIANS_API_CACHE_KEY_PREFIX, hashlib.md5(url.encode('utf-8')).hexdigest()) content = None if ignore_cache else cache.get(cache_key) if not content: try: request = urllib2.Request(url) response = urllib2.urlopen(request) content = response.read() cache.set(cache_key, content, cache_timeout) except urllib2.URLError as e: logging.error('Mozillians request failed:\n - %s\n - %s', e, url) return None try: return json.loads(content) except ValueError as e: logging.error('Parsing Mozillians response failed:\n - %s\n - %s', e, url) return None
def _method(self, method_name, args=None, additional_timeout=0, retry=0): """ Makes post-request to vk api witch burst protection and exception handling @type method_name: text_type @param method_name: vk api method name @param args: method parameters @param additional_timeout: time in seconds to wait before reattempting """ assert isinstance(method_name, text_type) if retry > MAX_API_RETRY: raise IncorrectApiResponse('reached max api retry for %s, %s' % (method_name, self.jid)) args = args or {} args.update({'v': self.VERSION, 'access_token': self.token}) _logger.debug('calling api method %s, arguments: %s' % (method_name, args)) time.sleep(additional_timeout) now = time.time() diff = now - self.last_method_time if diff < API_MAXIMUM_RATE: _logger.debug('burst protected') time.sleep(abs(diff - API_MAXIMUM_RATE)) self.last_method_time = now try: response = requests.post(self.URL % method_name, args) if response.status_code != 200: raise requests.HTTPError('incorrect response status code') body = json.loads(response.text) _logger.debug('got: %s' % body) if 'response' in body: return body['response'] if 'error' in body and 'error_code' in body['error']: code = body['error']['error_code'] raise api_errors.get(code, UnknownError()) raise NotImplementedError('unable to process %s' % body) except (requests.RequestException, ValueError) as e: _logger.error('method error: %s' % e) additional_timeout = additional_timeout or 1 except TooManyRequestsPerSecond: additional_timeout = additional_timeout or API_MAXIMUM_RATE / WAIT_RATE additional_timeout *= WAIT_RATE return self._method(method_name, args, additional_timeout, retry + 1)
def start(self): if self.polling: return _logger.debug('already polling %s' % self.user) self.polling = True args = self.user.vk.messages.get_lp_server() args['wait'] = 30 url = 'http://{server}?act=a_check&key={key}&ts={ts}&wait={wait}&mode=2'.format(**args) data = json.loads(requests.get(url).text) try: if not data['updates']: _logger.debug('no updates for %s' % self.user) for update in data['updates']: gevent.spawn(self.handle, update) except KeyError: _logger.error('unable to process %s' % data) self.polling = False if not self.user.is_client: return _logger.debug('ending polling for %s' % self.user) self.start()
def _render_fields(self, req, form_id, state): fields = json.loads(state is not None and state or '{}') rendered = [] for name, value in fields.iteritems(): if value == 'on': value = _("checked (checkbox)") elif value == '': value = _("empty (text field)") elif isinstance(value, str): value = "'".join(['', value, '']) else: # Still try to display something useful instead of corrupting # parent page beyond hope of recovery through the web_ui. value = "'".join(['', repr(value), '']) author, time = self.get_tracform_fieldinfo(form_id, name) author = format_author(self.env, req, author, 'value') rendered.append( {'name': name, 'value': value, 'author': tag.span(tag(_("by %(author)s", author=author)), class_='author'), 'time': time}) return rendered
def _render_values(state): fields = [] for name, value in json.loads(state or '{}').iteritems(): fields.append(name + ': ' + value) return '; '.join(fields)
except Exception, e: errors.append(traceback.format_exc()) else: if self.showErrors: textlines.extend(errors) textlines.append(line) textlines.extend(srciter) # Determine our destination context and load the current state. self.context = tuple([realm, resource_id, self.subcontext is not None and \ self.subcontext or '']) state = self.macro.get_tracform_state(self.context) self.formatter.env.log.debug('TracForms state = ' + (state is not None and state or '')) for name, value in json.loads(state or '{}').iteritems(): self.env[name] = value self.formatter.env.log.debug(name + ' = ' + to_unicode(value)) if self.subcontext is not None: self.env[self.subcontext + ':' + name] = value self.sorted_env = None (self.form_id, self.form_realm, self.form_resource_id, self.form_subcontext, self.form_updater, self.form_updated_on, self.form_keep_history, self.form_track_fields) = \ self.macro.get_tracform_meta(self.context) self.form_id = self.form_id is not None and int(self.form_id) or None # Wiki-ize the text, this will allow other macros to execute after # which we can do our own replacements within whatever formatted # junk is left over. text = self.wiki('\n'.join(textlines))
def addform(self, data): for name, value in json.loads(state or '{}').iteritems(): keys = [prefix + ':' + name for prefix in self.prefixes] for key in keys: self[key] = tuple(value)
except Exception, e: errors.append(traceback.format_exc()) else: if self.showErrors: textlines.extend(errors) textlines.append(line) textlines.extend(srciter) # Determine our destination context and load the current state. self.context = tuple([realm, resource_id, self.subcontext is not None and \ self.subcontext or '']) state = self.macro.get_tracform_state(self.context) self.formatter.env.log.debug( 'TracForms state = ' + (state is not None and state or '')) for name, value in json.loads(state or '{}').iteritems(): self.env[name] = _xml_escape(value) self.formatter.env.log.debug( name + ' = ' + to_unicode(value)) if self.subcontext is not None: self.env[self.subcontext + ':' + name] = value self.sorted_env = None (self.form_id, self.form_realm, self.form_resource_id, self.form_subcontext, self.form_updater, self.form_updated_on, self.form_keep_history, self.form_track_fields) = \ self.macro.get_tracform_meta(self.context) self.form_id = self.form_id is not None and int(self.form_id) or None # Wiki-ize the text, this will allow other macros to execute after # which we can do our own replacements within whatever formatted # junk is left over.
def save_tracform(self, src, state, author, base_version=None, keep_history=False, track_fields=False, cursor=None): cursor = self.get_cursor(cursor) (form_id, realm, resource_id, subcontext, last_updater, last_updated_on, form_keep_history, form_track_fields) = self.get_tracform_meta(src) if form_keep_history is not None: keep_history = form_keep_history old_state = self.get_tracform_state(src) if form_track_fields is not None: track_fields = form_track_fields if base_version is not None: base_version = int(base_version or 0) if ((base_version is None and last_updated_on is None) or (base_version == last_updated_on)): if state != old_state: updated_on = int(time.time()) if form_id is None: form_id = cursor(""" INSERT INTO forms (realm, resource_id, subcontext, state, author, time) VALUES (%s, %s, %s, %s, %s, %s) """, realm, resource_id, subcontext, state, author, updated_on) \ .last_id(cursor, 'forms', 'id') else: cursor( """ UPDATE forms SET state = %s, author = %s, time = %s WHERE id = %s """, state, author, updated_on, form_id) if keep_history: cursor( """ INSERT INTO forms_history (id, time, author, old_state) VALUES (%s, %s, %s, %s) """, form_id, last_updated_on, last_updater, old_state) if track_fields: # Break down old version and new version. old_fields = json.loads(old_state or '{}') new_fields = json.loads(state or '{}') updated_fields = [] for field, old_value in old_fields.iteritems(): if new_fields.get(field) != old_value: updated_fields.append(field) for field in new_fields: if old_fields.get(field) is None: updated_fields.append(field) self.log.debug('UPDATED: ' + str(updated_fields)) for field in updated_fields: if cursor( """ SELECT COUNT(*) FROM forms_fields WHERE id = %s AND field = %s""", form_id, field).value: cursor( """ UPDATE forms_fields SET author = %s, time = %s WHERE id = %s AND field = %s """, author, updated_on, form_id, field) else: cursor( """ INSERT INTO forms_fields (id, field, author, time) VALUES (%s, %s, %s, %s) """, form_id, field, author, updated_on) else: updated_on = last_updated_on author = last_updater return ((form_id, realm, resource_id, subcontext, state, author, updated_on), (form_id, realm, resource_id, subcontext, old_state, last_updater, last_updated_on)) else: raise ValueError(_("Conflict"))
def save_tracform(self, src, state, author, base_version=None, keep_history=False, track_fields=False, db=None): (form_id, realm, resource_id, subcontext, last_updater, last_updated_on, form_keep_history, form_track_fields) = self.get_tracform_meta(src, db=db) if form_keep_history is not None: keep_history = form_keep_history old_state = form_id and self.get_tracform_state(form_id) or '{}' if form_track_fields is not None: track_fields = form_track_fields if base_version is not None: base_version = int(base_version or 0) if ((base_version is None and last_updated_on is None) or (base_version == last_updated_on)): if state != old_state: updated_on = int(time.time()) db = self._get_db(db) cursor = db.cursor() if form_id is None: cursor.execute(""" INSERT INTO forms (realm, resource_id, subcontext, state, author, time) VALUES (%s, %s, %s, %s, %s, %s) """, (realm, resource_id, subcontext, state, author, updated_on)) form_id = db.get_last_id(cursor, 'forms') else: cursor.execute(""" UPDATE forms SET state=%s, author=%s, time=%s WHERE id=%s """, (state, author, updated_on, form_id)) if keep_history: cursor.execute(""" INSERT INTO forms_history (id, time, author, old_state) VALUES (%s, %s, %s, %s) """, (form_id, last_updated_on, last_updater, old_state)) if track_fields: # Break down old version and new version. old_fields = json.loads(old_state) new_fields = json.loads(state or '{}') updated_fields = [] for field, old_value in old_fields.iteritems(): if new_fields.get(field) != old_value: updated_fields.append(field) for field in new_fields: if old_fields.get(field) is None: updated_fields.append(field) self.log.debug('UPDATED: ' + str(updated_fields)) for field in updated_fields: cursor.execute(""" SELECT COUNT(*) FROM forms_fields WHERE id=%s AND field=%s""", (form_id, field)) if cursor.fetchone()[0] > 0: cursor.execute(""" UPDATE forms_fields SET author=%s, time=%s WHERE id=%s AND field=%s """, (author, updated_on, form_id, field)) else: cursor.execute(""" INSERT INTO forms_fields (id, field, author, time) VALUES (%s, %s, %s, %s) """, (form_id, field, author, updated_on)) db.commit() else: updated_on = last_updated_on author = last_updater return ((form_id, realm, resource_id, subcontext, state, author, updated_on), (form_id, realm, resource_id, subcontext, old_state, last_updater, last_updated_on)) else: raise ValueError(_("Conflict"))
def parse_history(changes, fieldwise=False): """Versatile history parser for TracForms. Returns either a list of dicts for changeset display in form view or a dict of field change lists for stepwise form reset. """ fieldhistory = {} history = [] if not fieldwise == False: def _add_change(fieldhistory, field, author, time, old, new): if field not in fieldhistory.keys(): fieldhistory[field] = [{'author': author, 'time': time, 'old': old, 'new': new}] else: fieldhistory[field].append({'author': author, 'time': time, 'old': old, 'new': new}) return fieldhistory new_fields = None for changeset in changes: # break down old and new version try: old_fields = json.loads(changeset.get('old_state', '{}')) except ValueError: # skip invalid history old_fields = {} pass if new_fields is None: # first loop cycle: only load values for comparison next time new_fields = old_fields last_author = changeset['author'] last_change = changeset['time'] continue updated_fields = {} for field, old_value in old_fields.iteritems(): new_value = new_fields.get(field) if new_value != old_value: if fieldwise == False: change = _render_change(old_value, new_value) if change is not None: updated_fields[field] = change else: fieldhistory = _add_change(fieldhistory, field, last_author, last_change, old_value, new_value) for field in new_fields: if old_fields.get(field) is None: if fieldwise == False: change = _render_change(None, new_fields[field]) if change is not None: updated_fields[field] = change else: fieldhistory = _add_change(fieldhistory, field, last_author, last_change, None, new_fields[field]) new_fields = old_fields history.append({'author': last_author, 'time': format_datetime(last_change), 'changes': updated_fields}) last_author = changeset['author'] last_change = changeset['time'] return fieldwise == False and history or fieldhistory
def _render_values(state, delimiter=': '): fields = [] for name, value in json.loads(state or '{}').iteritems(): fields.append(''.join([name, delimiter, value])) return '; '.join(fields)