def get(self, table_id=None, additional_query=None): self._method_validate("GET") query = (self._db[self.data["table_name"]].is_active == True if "is_active" in self._db[self.data["table_name"]].fields else self._db[self.data["table_name"]].id > 0) if table_id: query &= self._db[self.data["table_name"]].id == table_id if self.data["GET"].get("queryable_fields") and additional_query: for k, v in additional_query.items(): if k in self.data["GET"]["queryable_fields"]: query &= self._db[self.data["table_name"]][k] == v else: raise HTTP( 400, "{field} is not a searchable field".format(field=k)) result = self._db(query).select( self._db[self.data["table_name"]].id, *[ self._db[self.data["table_name"]][each] for each in self.data["GET"].get("selectors", []) ]) if table_id: if result: return result.first() raise HTTP(404, "no record found") return result
def __orderby(self): """ :raises HTTP: http.BAD_REQUEST :rtype: str """ order_field = self.request_vars["orderby"] sort_order = self.request_vars['sort'] or 'ASC' if order_field: order_field = order_field.lower() # todo: Essa é a melhor forma ? if order_field not in self.table.fields: headers = {"InvalidParameters": json(order_field)} raise HTTP( http.BAD_REQUEST, "%s não é um campo válido para ordenação." % order_field, **headers) if sort_order not in self.__sorting_options: headers = {"InvalidParameters": json(sort_order)} raise HTTP(http.BAD_REQUEST, "%s não é uma ordenacão válida." % sort_order, **headers) return "%s %s" % (self.table[order_field], sort_order) elif self.table._primarykey: return self.table._primarykey return self.table.fields[0]
def execute(self): """ O método realiza a remoção de uma entrada no banco de dados e retorna HTTP Status Code 200 (OK) caso o conteúdo seja removido com sucesso. A chave primária deve estar contida na lista de parâmetros e a mesma é utilizada para remoção. :rtype : HTTP :raise HTTP: 422 Ocorre haja incompatibilidade entre o tipo de dados da coluna e o valor passsado :raise HTTP: 404 A chave primária informada é inválida e nenhuma entrada foi afetada :raise HTTP: 403 A linha requisitada não pode ser deletada porque possui dependências que não foram atendidas """ try: conditions = [ self.p_key_fields[field] == valor for field, valor in self.identifiers_values ] affected_rows = self.db(reduce(lambda a, b: (a & b), conditions)).delete() print(self.db._lastsql) except Exception: self.db.rollback() raise HTTP(http.INTERNAL_SERVER_ERROR, "Não foi possível deletar.") if affected_rows == 0: raise HTTP(http.NO_CONTENT, "Ooops... A princesa está em um castelo com outro ID.") else: self.db.commit() headers = {"Affected": affected_rows} raise HTTP(http.OK, "Conteúdo atualizado com sucesso", **headers)
def wrapper(*args, **kwargs): if (type(request_type) is list) and (current.request.env.request_method not in request_type): raise HTTP(400) elif (type(request_type) is not list) and (current.request.env.request_method != request_type): raise HTTP(400) else: return f(*args, **kwargs)
def g(data): try: output = f(data) return XML(ouput) except (TypeError, ValueError) as e: raise HTTP(405, '%s serialization error' % e) except ImportError as e: raise HTTP(405, '%s not available' % e) except Exception as e: raise HTTP(405, '%s error' % e)
def execute(self): blob_fields = self.blob_fields(self.parameters) parameters = self.content_with_valid_parameters blob_values = self.blob_values(parameters, blob_fields) try: if not blob_fields: if self.has_composite_primary_key: self.table.insert(**parameters) # TODO O que podemos retornar no caso de sucesso que faça sentido? new_id = 1 else: new_id = self.table.insert( **parameters)[self._unique_identifier_column] else: if self.has_composite_primary_key: raise NotImplementedError # TODO Precisa atualizar o JAR que faz inserção para lidar id composta stmt = self.table._insert(**parameters) # Essa inserção funcionará. É necessário reinserir pelo Java pois o arquivo ficará corrompido self.db.executesql(stmt, blob_values) new_id = parameters[self._unique_identifier_column] if self.observer: self.observer.did_finish_successfully(self, parameters) except Exception as e: print(self.db._lastsql) print(e) self.db.rollback() if self.observer: self.observer.did_finish_with_error(self, parameters, e) raise HTTP(http.BAD_REQUEST, "Não foi possível completar a operação.") else: self.db.commit() if new_id and blob_fields: gambiarras.insert_blob(new_id, zip(blob_fields, blob_values), self.table, self._unique_identifier_column) # self.insert_blob_fields_callback(new_id, zip(blob_fields, blob_values)) # Reinsere blobs pelo JAVA headers = { "Location": "%s?%s=%i" % (self.base_endpoint_uri, self._unique_identifier_column, new_id), "id": new_id } raise HTTP(http.CREATED, "Conteúdo inserido com sucesso.", **headers)
def post(self, data): self._method_validate("POST") if self.data["POST"].get("allowed_fields") and any([ each not in self.data["POST"]["allowed_fields"] for each in data.keys() ]): raise HTTP(400, "unallowed POST field") if not self.data["POST"]["allow_duplicates"] and self._db[ self.data["table_name"]](**data): raise HTTP(400, "duplicate record exists") return self._db[self.data["table_name"]].insert(**data)
def diff(): item = application.getItemByUUID(request.args(0)) if item is None: raise HTTP(404) content = db.plugin_text_text(item_id=item.unique_id) archive = db.plugin_text_text_archive(request.args(1)) fields = [] fields_archived = [] fields_names = [] for f in db.plugin_text_text: # if values diff if content[f.name] != archive[f.name]: fields_names.append(f.name) f.comment = None fields.append(f) db.plugin_text_text_archive[f.name].comment = None fields_archived.append(db.plugin_text_text_archive[f.name]) # build two readonly forms form_actual = SQLFORM.factory(*fields, record=content, readonly=True, showid=False, formstyle='divs') form_archive = SQLFORM.factory(*fields, record=archive, readonly=True, showid=False, formstyle='divs') return locals()
def index(): item = application.getItemByUUID(request.args(0)) if item is None: raise HTTP(404) short = request.vars.short if request.vars.short is not None else False tbl = db.plugin_comment_comment tbl.item_id.default = item.unique_id form = SQLFORM(tbl, submit_button=T('Comment'), formstyle='bootstrap3_stacked') rows = db((tbl.id > 0) & (tbl.item_id == item.unique_id)).select( orderby=~tbl.created_on) if form.process().accepted: response.js = "jQuery('#%s').get(0).reload();" % request.cid # send notifications to the users, except the current one subject = T("Comments on %s", (item.headline, )) # get the comment body comment = tbl(form.vars.id) message = response.render( 'plugin_comment/someone_commented.txt', dict(item=item, comment=comment, user=auth.user)) application.notifyCollaborators(item.unique_id, subject, message) return dict(form=form, comments=rows, short=short, item=item)
def get_database_string(self): db_type = self.database.get("db_type", "sqlite").lower() pool_size = self.database.get("pool_size", 30) if (db_type == "sqlite"): db_string = "sqlite://storage.db" elif (db_type == "mysql"): db_string = "mysql://%s:%s@%s:%s/%s" % \ (self.database.get("username", "sahana"), self.database.get("password", "password"), self.database.get("host", "localhost"), self.database.get("port", None) or "3306", self.database.get("database", "sahana")) elif (db_type == "postgres"): db_string = "postgres://%s:%s@%s:%s/%s" % \ (self.database.get("username", "sahana"), self.database.get("password", "password"), self.database.get("host", "localhost"), self.database.get("port", None) or "5432", self.database.get("database", "sahana")) else: from gluon import HTTP raise HTTP( 501, body= "Database type '%s' not recognised - please correct file models/000_config.py." % db_type) return (db_string, pool_size)
def login_url(self, next="/"): """ Overriding to produce a different redirect_uri """ if not self.accessToken(): request = current.request session = current.session if not request.vars.code: session.redirect_uri = self.args["redirect_uri"] data = { "redirect_uri": session.redirect_uri, "response_type": "code", "client_id": self.client_id, } if self.args: data.update(self.args) auth_request_url = "%s?%s" % ( self.auth_url, urlencode(data), ) raise HTTP( 307, REDIRECT_MSG % auth_request_url, Location=auth_request_url, ) else: session.code = request.vars.code self.accessToken() return next
def __oauth_login(self, next): """ This method redirects the user to the authenticating form on authentication server if the authentication code and the authentication token are not available to the application yet. Once the authentication code has been received this method is called to set the access token into the session by calling accessToken() """ token = self.accessToken() if not token: current.session.redirect_uri = self.__redirect_uri(next) data = dict(redirect_uri=current.session.redirect_uri, response_type='code', client_id=self.client_id) if self.args: data.update(self.args) auth_request_url = self.auth_url + "?" + urlencode(data) raise HTTP( 302, "You are not authenticated: you are being redirected to the <a href='" + auth_request_url + "'> authentication server</a>", Location=auth_request_url) return
def _method_validate(self, method): if method not in self.data["supported_methods"]: raise HTTP( 405, "'{method}' method is not supported by this API".format( method=method), )
def __init__(self, api_key, request, endpoint, lower_vars): """ :type endpoint: str :type request: Request :type api_key: key.APIKey """ self.request = request self.HTTPMethod = self.request.env.request_method self.db = current.db self.cache = (current.cache.ram, 86400) self.datasource = current.datasource self.timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S') self.api_key = api_key self.path_info = self.request.env.PATH_INFO self.endpoint = endpoint if not self.endpoint: raise HTTP(404, "Recurso requisitado é inválido") self.lower_vars = lower_vars self.parameters = self._validate_fields() self.return_fields = self._validate_return_fields() self.valid_content_types = { 'JSON': 'application/json; charset=%s' % self.datasource._db_codec, 'XML': 'text/xml', 'HTML': 'text/html', 'DEFAULT': 'application/json; charset=%s' % self.datasource._db_codec }
def _validate_fields(self): """ Método que verifica se os parâmetros passados são válidos ou não. Um dicionário com duas chaves é retornado: `valid` uma lista de campos cujos nomes estão contidos na lista de colunas da tabela requisitada `special` uma lista de campos cujos nomes, com um sufixo válido, estão contidos na lista de colunas da tabela requisitada :rtype : dict :return: Um dicionário contendo os campos válidos """ endpoint_fields = self.datasource[self.endpoint].fields fields = {"valid": [], "special": []} invalid_fields = [] for k in self.lower_vars.keys(): if k in endpoint_fields: fields['valid'].append(k) elif self._is_valid_field_with_sufix(k): fields['special'].append(k) else: if k not in self.valid_parameters: invalid_fields.append(k) if invalid_fields: headers = {"InvalidParameters": json(invalid_fields)} raise HTTP(http.BAD_REQUEST, "Alguns parâmetros da requisição são incompatíveis.", **headers) return fields
def share(): """ Show the list of desk to with the item can be push """ item = application.getItemByUUID(request.args(0)) if item is None: raise HTTP(404) query = (db.desk.id != session.desk_id) query &= auth.accessible_query('push_items', db.desk) posible_desk = db(query).select() fld_to_desk = Field('to_desk', 'integer') fld_to_desk.label = T("Push to") fld_to_desk.comment = T("Select where to push the item") fld_to_desk.requires = IS_IN_SET([(desk.id, desk.name) for desk in posible_desk]) form = SQLFORM.factory(fld_to_desk, submit_button=T("Send"), table_name='share') if form.process().accepted: # send the item to the selected desk ct = application.getContentType(item.item_type) ct.shareItem(item.unique_id, session.desk_id, form.vars.to_desk) response.js = "$('#metaModal').modal('hide');" return locals()
def perform_request(self): """ Método principal, define a ordem e forma de execução de uma requisição a API :return: depende do tipo de dado requisitado. Padrão é validResponseFormats['DEFAULT'] """ try: methods = { 'GET': APIQuery, 'POST': APIInsert, 'PUT': APIUpdate, 'DELETE': APIDelete } operation = methods[self.HTTPMethod](self) except KeyError: raise HTTP(http.METHOD_NOT_ALLOWED, "Método não suportado") thread.start_new_thread(self.__save_log, tuple()) self._define_response_return_type() if self.__is_notifyable_operation(operation): operation.observer = WebsocketNotificator() return operation.execute()
def login_url(self, next="/"): """ Overriding to produce a different redirect_uri """ if not self.accessToken(): request = current.request session = current.session if not request.vars.code: session.redirect_uri = "%s/%s/default/facebook/login" % \ (current.deployment_settings.get_base_public_url(), request.application) data = dict(redirect_uri=session.redirect_uri, response_type="code", client_id=self.client_id) if self.args: data.update(self.args) auth_request_url = "%s?%s" % (self.auth_url, urllib.urlencode(data)) raise HTTP(307, "You are not authenticated: you are being redirected to the <a href='%s'> authentication server</a>" % \ auth_request_url, Location=auth_request_url) else: session.code = request.vars.code self.accessToken() #return session.code return next
def share(): """ Show the list of desk to with the item can be push """ item = application.getItemByUUID(request.args(0)) if item is None: raise HTTP(404) query = (db.desk.id != session.desk_id) query &= auth.accessible_query('push_items', db.desk) posible_desk = db(query).select() fld_to_desk = Field('to_desk', 'integer') fld_to_desk.label = T("Push to organization desk") fld_to_desk.comment = T("Select where to push the item") fld_to_desk.requires = IS_EMPTY_OR( IS_IN_SET([(desk.id, desk.name) for desk in posible_desk])) fld_personal_desk = Field('to_person_desk', 'integer') fld_personal_desk.label = T("Push to other person desk") fld_personal_desk.comment = T("Select a person from the list.") # list of person on orgs persons = [] # search up all the persons orgs = db(db.organization.users.contains(auth.user.id)).select() for org in orgs: x = [db.auth_user(id=y) for y in org.users if y != auth.user.id] persons.extend(x) persons = list(set(persons)) fld_personal_desk.requires = IS_EMPTY_OR( IS_IN_SET([(per.id, "{} {}".format(per.first_name, per.last_name)) for per in persons])) fld_cond = Field('cond', 'boolean', default=False) fld_cond.label = T('To other person?') form = SQLFORM.factory(fld_to_desk, fld_personal_desk, fld_cond, submit_button=T("Send"), table_name='share') if form.process().accepted: src = session.desk_id if form.vars.cond: # send the item to other user other_user = db.auth_user(form.vars.to_person_desk) target = application.getUserDesk(other_user).id else: # send the item to the selected desk target = form.vars.to_desk if target: ct = application.getContentType(item.item_type) ct.shareItem(item.unique_id, src, target) response.js = "$('#metaModal').modal('hide');" response.flash = None return locals()
def async (self, task, args=[], vars={}, timeout=300): """ Wrapper to call an asynchronous task. - run from the main request @param task: The function which should be run - async if a worker is alive @param args: The list of unnamed args to send to the function @param vars: The list of named vars to send to the function @param timeout: The length of time available for the task to complete - default 300s (5 mins) """ # Check that task is defined tasks = current.response.s3.tasks if not tasks: return False if task not in tasks: return False # Check that worker is alive if not self._is_alive(): # Run the task synchronously _args = [] for arg in args: if isinstance(arg, (int, long, float)): _args.append(str(arg)) elif isinstance(arg, basestring): _args.append("%s" % str(json.dumps(arg))) else: raise HTTP(501, "Unhandled arg type") args = ",".join(_args) _vars = ",".join( ["%s=%s" % (str(var), str(vars[var])) for var in vars]) if args: statement = "tasks['%s'](%s,%s)" % (task, args, _vars) else: statement = "tasks['%s'](%s)" % (task, _vars) # Handle JSON null = None exec(statement) return None auth = current.auth if auth.is_logged_in(): # Add the current user to the vars vars["user_id"] = auth.user.id # Run the task asynchronously record = current.db.scheduler_task.insert( application_name="%s/default" % current.request.application, task_name=task, function_name=task, args=json.dumps(args), vars=json.dumps(vars), timeout=timeout) # Return record so that status can be polled return record
def execute(self): """ O método realiza uma atualização de uma entrada no banco de dados e retorna HTTP Status Code 200 (OK) caso o conteúdo seja atualizado com sucesso. A chave primária deve estar contida na lista de parâmetros e a mesma é utilizada para atualização. :rtype : HTTP :raise HTTP: 204 Não é possível realizar uma atualização sem que parâmetros sejam passados :raise HTTP: 422 Ocorre haja incompatibilidade entre o tipo de dados da coluna e o valor passsado :raise HTTP: 404 A chave primária informada é inválida e nenhuma entrada foi afetada """ parameters = self.content_with_valid_parameters # TODO Funciona atualização de blob? blob_fields = self.blob_fields(self.parameters) conditions = [ self.p_key_fields[field] == valor for field, valor in self.identifiers_values ] try: if not blob_fields: affected_rows = self.db( reduce(lambda a, b: (a & b), conditions)).update(**parameters) else: stmt = self.db(reduce(lambda a, b: (a & b), conditions))._update(**parameters) affected_rows = self.db.executesql( stmt, self.blob_values(parameters, blob_fields)) # TODO As entradas são atualizadas corretamente, mas rowcount retorna -1 O.o except Exception as e: if self.observer: self.observer.did_finish_with_error(self, parameters, e) self.db.rollback() if isinstance(e, SyntaxError): raise HTTP(http.NO_CONTENT, "Nenhum conteúdo foi passado") else: raise HTTP(http.UNPROCESSABLE_ENTITY, "Algum parâmetro possui tipo inválido") else: self.db.commit() if self.observer: parameters.update(self.identifiers_values) self.observer.did_finish_successfully(self, parameters) headers = {"Affected": affected_rows} raise HTTP(http.OK, "Conteúdo atualizado com sucesso", **headers)
def DELETE(*reqargs, **reqvars): try: validate(instance=reqvars, schema=schema) except ValidationError: raise HTTP(400, "InvalidParameterException") group_name = reqvars["GroupName"] return response.json(Cognito().delete_group(group_name))
def PATCH(*reqargs, **reqvars): try: validate(instance=reqvars, schema=schema) except ValidationError: raise HTTP(400, "InvalidParameterException") username = reqvars["Username"] group_name = reqvars["GroupName"] return response.json(Cognito().add_user_to_group(username, group_name))
def POST(*reqargs, **reqvars): try: validate(instance=reqvars, schema=schema) except ValidationError: raise HTTP(400, "InvalidParameterException") group_name = reqvars["GroupName"] description = reqvars["Description"] return response.json(Cognito().create_group(group_name, description))
def _get_query_statement(self): """ O método gera diferentes tipos de consultas para tipos de dados diferentes. Cada tipo de dado gera uma condição diferente e própria para o seu tipo. :rtype : list :return: Uma lista de parâmetros processados de consulta """ conditions = [] if not self.fields and self.request.id_from_path: conditions.append(self.table[self._unique_identifier_column] == self.request.id_from_path) return conditions # Consultas normais for field in self.fields: if self.table[field].type == 'string': try: if isinstance(self.request_vars[field], list): # TODO: PYTHON 2.x DOESN'T SUPPORT .lower() of unicode strings. lower_encoded_field = map( lambda x: self._utf8_lower(x), self.request_vars[field]) else: # TODO PYTHON 2.x DOESN'T SUPPORT .lower() of unicode strings. lower_encoded_field = self._utf8_lower( self.request_vars[field]) conditions.append(self.table[field].contains( lower_encoded_field, case_sensitive=False, all=True)) except UnicodeDecodeError: headers = {"InvalidEncoding": json(dict(campo=field))} raise HTTP( http.BAD_REQUEST, "Encoding do parâmetro é inválido (tem certeza que é utf-8?)", **headers) else: conditions.append( self.table[field] == self.request_vars[field]) # Trata condições especiais for special_field in self.special_fields: field = self.request.special_field_chop(special_field) if field: if special_field.endswith('_min'): conditions.append( self.table[field] > self.request_vars[special_field]) elif special_field.endswith('_max'): conditions.append( self.table[field] < self.request_vars[special_field]) elif special_field.endswith('_set'): conditions.append(self.table[field].belongs( self.request_vars[special_field])) return conditions
def __init__(self, request): """ Classe responsável por lidar com requisições do tipo POST, que serão transformadas em um INSERT no banco de dados e retornarão uma resposta HTTP adequada a criação do novo recurso. :type request: APIRequest """ super(APIInsert, self).__init__(request) if self.has_composite_primary_key and not self.primary_key_in_parameters( self.parameters): raise HTTP( http.BAD_REQUEST, "Não é possível inserir um conteúdo sem sua chave primária composta." ) if not self.has_composite_primary_key and self.primary_key_in_parameters( self.parameters): raise HTTP( http.BAD_REQUEST, "Não é possível inserir um conteúdo com sua chave primária.")
def add_user_to_group(self, username, group_name): user = self.db(self.db.auth_user.username == username).select() if not len(user): raise HTTP(400, "UserNotFoundException") group = self.db(self.db.auth_group.role == group_name).select() if len(group): self.auth.add_membership(group.first().id, user.first().id) return None
def POST(*reqargs, **reqvars): try: validate(instance=reqvars, schema=schema) except ValidationError: raise HTTP(400, "InvalidParameterException") username = reqvars["Username"] password = reqvars["Password"] user_attributes = reqvars.get("UserAttributes") return response.json(Cognito().sign_up(username, password, user_attributes))
def pdflatex_from_html(html): if os.system('which pdflatex > /dev/null') == 0: markmin = TAG(html).element('body').flatten(markmin_serializer) out, warnings, errors = markmin2pdf(markmin) if errors: current.response.headers['Content-Type'] = 'text/html' raise HTTP(405, HTML(BODY(H1('errors'), UL(*errors), H1('warnings'), UL(*warnings))).xml()) else: return XML(out)
def diff(): """ Show the diff betwen the actual item and the archive one """ item = application.getItemByUUID(request.args(0)) if item is None: raise HTTP(404) item_archive = db.item_archive(request.args(1)) if item_archive is None: raise HTTP(503) fields = [] fields_archived = [] # allow view of administrative metadata db.item.modified_by.readable = True db.item.modified_on.readable = True db.item_archive.modified_by.readable = True db.item_archive.modified_on.readable = True for f in db.item: if item[f.name] != item_archive[f.name]: f.comment = None fields.append(f) db.item_archive[f.name].comment = None fields_archived.append(db.item_archive[f.name]) # build two readonly forms form_actual = SQLFORM.factory(*fields, record=item, readonly=True, showid=False, formstyle='divs') form_archive = SQLFORM.factory(*fields_archived, record=item_archive, readonly=True, showid=False, formstyle='divs') return dict(item=item, form_actual=form_actual, form_archive=form_archive)