예제 #1
0
    def api(path):
        # this is not final, requires pydal 19.5
        args = path.split("/")
        app_name = args[0]
        if MODE != "full":
            raise HTTP(403)
        module = Reloader.MODULES[app_name]

        def url(*args):
            return request.url + "/" + "/".join(args)

        databases = [
            name for name in dir(module)
            if isinstance(getattr(module, name), DAL)
        ]
        if len(args) == 1:

            def tables(name):
                db = getattr(module, name)
                return [{
                    "name": t._tablename,
                    "fields": t.fields,
                    "link": url(name, t._tablename) + "?model=true",
                } for t in getattr(module, name)]

            return {
                "databases": [{
                    "name": name,
                    "tables": tables(name)
                } for name in databases]
            }
        elif len(args) > 2 and args[1] in databases:
            db = getattr(module, args[1])
            id = args[3] if len(args) == 4 else None
            policy = Policy()
            for table in db:
                policy.set(
                    table._tablename,
                    "GET",
                    authorize=True,
                    allowed_patterns=["**"],
                    allow_lookup=True,
                    fields=table.fields,
                )
                policy.set(table._tablename,
                           "PUT",
                           authorize=True,
                           fields=table.fields)
                policy.set(table._tablename,
                           "POST",
                           authorize=True,
                           fields=table.fields)
                policy.set(table._tablename, "DELETE", authorize=True)

            # must wrap into action uses to make sure it closes transactions
            data = action.uses(db)(lambda: RestAPI(db, policy)(
                request.method, args[2], id, request.query, request.json))()
        else:
            data = {}
        if "code" in data:
            response.status = data["code"]
        return data
예제 #2
0
 def checkout(project, commit):
     if not is_git_repo(project):
         raise HTTP(400)
     run("git stash", project)
     run("git checkout " + commit, project)
     Reloader.import_app(project)
예제 #3
0
    def __init__(self,
                 table,
                 record=None,
                 readonly=False,
                 deletable=True,
                 noncreate=False,
                 formstyle=FormStyleDefault,
                 dbio=True,
                 keep_values=False,
                 form_name=None,
                 hidden=None,
                 validation=None,
                 csrf_session=None,
                 csrf_protection=True,
                 lifespan=None,
                 signing_info=None,
                 submit_value="Submit",
                 **kwargs):
        self.param = Param(
            formstyle=formstyle,
            hidden=hidden,
            submit_value=submit_value,
            sidecar=[],
        )

        if isinstance(table, list):
            dbio = False
            # Mimic a table from a list of fields without calling define_table
            form_name = form_name or "none"
            for field in table:
                field.tablename = getattr(field, "tablename", form_name)

        if isinstance(record, (int, str)):
            record_id = int(str(record))
            self.record = table[record_id]
            if not self.record:
                raise HTTP(404)
        else:
            self.record = record

        # computed from input and not changed
        self.table = table
        self.deletable = self.record and deletable and not readonly
        self.dbio = dbio
        self.keep_values = True if keep_values or self.record else False
        self.form_name = form_name or table._tablename
        self.csrf_session = csrf_session
        self.signing_info = signing_info
        self.validation = validation
        self.lifespan = lifespan
        self.csrf_protection = csrf_protection
        # initialized and can change
        self.vars = {}
        self.errors = {}
        self.readonly = readonly
        self.noncreate = noncreate
        self.submitted = False
        self.deleted = False
        self.accepted = False
        self.formkey = None
        self.cached_helper = None
        self.action = None

        self.kwargs = kwargs if kwargs else {}

        if readonly or request.method == "GET":
            if self.record:
                self.vars = self._read_vars_from_record(table)
        else:
            post_vars = request.POST
            self.vars = copy.deepcopy(request.forms)
            self.submitted = True
            process = False

            # We only a process a form if it is POST and the formkey matches (correct formname and crsf)
            # Notice: we never expose the crsf uuid, we only use to sign the form uuid
            if request.method == "POST":
                if not self.csrf_protection or self._verify_form(post_vars):
                    process = True
            if process:
                record_id = self.record and self.record.get("id")
                if not post_vars.get("_delete"):
                    validated_vars = {}
                    uploaded_files = []
                    for field in self.table:
                        if field.writable and field.type != "id":
                            original_value = post_vars.getall(field.name)
                            if isinstance(original_value, list):
                                if len(original_value) == 1:
                                    original_value = original_value[0]

                                elif len(original_value) == 0:
                                    original_value = None
                            if field.type.startswith("list:") and isinstance(
                                    original_value, str):
                                try:
                                    original_value = json.loads(original_value
                                                                or "[]")
                                except json.decoder.JSONDecodeError:
                                    # this happens if posting a single value
                                    pass
                            (value,
                             error) = field.validate(original_value, record_id)
                            if field.type == "password" and record_id and value is None:
                                continue
                            if field.type == "upload":
                                value = request.files.get(field.name)
                                print(str(value)[:100])
                                delete = post_vars.get("_delete_" + field.name)
                                if value is not None:
                                    if field.uploadfolder:
                                        uploaded_files.append(
                                            tuple((field, value)))
                                    validated_vars[field.name] = value
                                elif self.record:
                                    if not delete:
                                        validated_vars[
                                            field.name] = self.record.get(
                                                field.name)
                                    else:
                                        validated_vars[field.name] = None
                            elif field.type == "boolean":
                                validated_vars[field.name] = value is not None
                            else:
                                validated_vars[field.name] = value
                            if error:
                                self.errors[field.name] = error
                    self.vars.update(validated_vars)
                    if validation:
                        validation(self)
                    if self.record and dbio:
                        self.vars["id"] = self.record.id
                    if not self.errors:
                        for file in uploaded_files:
                            field, value = file
                            value = field.store(value.file, value.filename,
                                                field.uploadfolder)
                            if value is not None:
                                validated_vars[field.name] = value
                        self.accepted = True
                        self.vars.update(validated_vars)
                        if dbio:
                            self.update_or_insert(validated_vars)
                elif dbio:
                    self.deleted = True
                    self.record.delete_record()
            elif self.record:
                # This form should not be processed.  We return the same as for GET.
                self.vars = self._read_vars_from_record(table)
        if self.csrf_protection:
            self._sign_form()
예제 #4
0
파일: auth.py 프로젝트: laurentis/py4web
 def form(self, name, **attr):
     form_factory = getattr(self.form_source, name, None)
     if not form_factory:
         raise HTTP(404)
     return form_factory()
예제 #5
0
def page_with_raise():
    raise HTTP(400, "oops")
예제 #6
0
파일: grid.py 프로젝트: JMBeresford/py4web
    def process(self):
        query = None
        db = self.db
        if not self.param.search_form and self.param.search_queries:
            search_type = safe_int(request.query.get("search_type", 0),
                                   default=0)
            search_string = request.query.get("search_string")
            if search_type < len(self.param.search_queries) and search_string:
                query_lambda = self.param.search_queries[search_type][1]
                try:
                    query = query_lambda(search_string)
                except:
                    pass  # flash a message here

        if not query:
            query = self.param.query
        else:
            query &= self.param.query

        parts = self.path.split("/")
        self.action = parts[0] or "select"
        self.tablename = self.get_tablenames(
            self.param.query)[0]  # what if there ar 2?
        self.record_id = safe_int(parts[1] if len(parts) > 1 else None,
                                  default=None)

        if self.param.fields:
            if not isinstance(self.param.fields, list):
                self.param.fields = [self.param.fields]
        else:
            table = db[self.tablename]
            self.param.fields = [field for field in table if field.readable]

        self.readonly_fields = [
            field for field in self.param.fields if not field.writable
        ]
        self.referrer = None

        if not self.tablename:
            raise HTTP(400)

        if self.action in ["new", "details", "edit"]:

            # SECURITY: if the record does not exist or does not match query, than we are not allowed
            if self.record_id:
                if (db((db[self.tablename]._id == self.record_id)
                       & self.param.query).count() == 0):
                    redirect(self.endpoint)  ## maybe flash

            readonly = self.action == "details"
            for field in self.readonly_fields:
                db[field.tablename][field.name].writable = False

            if not self.param.show_id:
                #  if not show id, find the "id" field and set readable/writable to False
                for field in db[self.tablename]:
                    if field.type == "id":
                        db[self.tablename][field.name].readable = False
                        db[self.tablename][field.name].writable = False

            self.form = Form(
                db[self.tablename],
                record=self.record_id,
                readonly=readonly,
                formstyle=self.param.formstyle,
            )
            if self.action == "new":
                if self.param.new_sidecar:
                    self.form.param.sidecar.append(self.param.new_sidecar)
                if self.param.new_submit_value:
                    self.form.param.submit_value = self.param.new_submit_value
            if self.action == "details":
                if self.param.details_sidecar:
                    self.form.param.sidecar.append(self.param.details_sidecar)
                if self.param.details_submit_value:
                    self.form.param.submit_value = self.param.details_submit_value
            if self.action == "edit":
                if self.param.edit_sidecar:
                    self.form.param.sidecar.append(self.param.edit_sidecar)
                if self.param.edit_submit_value:
                    self.form.param.submit_value = self.param.edit_submit_value

            # SECURITY: if the new record was created but does not match filter, delete it
            if self.form.accepted and not self.record_id:
                new_record = db[self.tablename]._id == self.form.vars["id"]
                if db(new_record & self.param.query).count() == 0:
                    db(new_record).delete()
                    # TODO: SHOULD FLASH SOME MESSAGE
            # redirect to the referrer
            if self.form.accepted or (readonly and request.method == "POST"):
                referrer = request.query.get("_referrer")
                if referrer:
                    redirect(
                        base64.b16decode(
                            referrer.encode("utf8")).decode("utf8"))
                else:
                    redirect(self.endpoint)

        elif self.action == "delete":
            db(db[self.tablename].id == self.record_id).delete()
            redirect(self.endpoint)

        elif self.action == "select":
            self.referrer = "_referrer=%s" % base64.b16encode(
                request.url.encode("utf8")).decode("utf8")

            #  find the primary key of the primary table
            pt = db[self.tablename]
            key_is_missing = True
            for field in self.param.fields:
                if (field.table._tablename == pt._tablename
                        and field.name == pt._id.name):
                    key_is_missing = False
            if key_is_missing:
                #  primary key wasn't included, add it and set show_id to False so it doesn't display
                self.param.fields.append(pt._id)
                self.param.show_id = False

            self.current_page_number = safe_int(request.query.get("page"),
                                                default=1)

            select_params = dict()
            #  try getting sort order from the request
            sort_order = request.query.get("orderby", "")

            try:
                parts = sort_order.lstrip("~").split(".")
                orderby = db[parts[0]][parts[1]]
                if sort_order.startswith("~"):
                    orderby = ~orderby
                select_params["orderby"] = orderby
            except (IndexError, KeyError, TypeError, AttributeError):
                select_params["orderby"] = self.param.orderby

            if self.param.left:
                select_params["left"] = self.param.left

            if self.param.left:
                # TODO: maybe this can be made more efficient
                self.total_number_of_rows = len(
                    db(query).select(db[self.tablename].id, **select_params))
            else:
                self.total_number_of_rows = db(query).count()

            #  if at a high page number and then filter causes less records to be displayed, reset to page 1
            if (self.current_page_number -
                    1) * self.param.rows_per_page > self.total_number_of_rows:
                self.current_page_number = 1

            if self.total_number_of_rows > self.param.rows_per_page:
                self.page_start = self.param.rows_per_page * (
                    self.current_page_number - 1)
                self.page_end = self.page_start + self.param.rows_per_page
                select_params["limitby"] = (self.page_start, self.page_end)
            else:
                self.page_start = 0
                if self.total_number_of_rows > 1:
                    self.page_start = 1
                self.page_end = self.total_number_of_rows

            if self.param.fields:
                self.rows = db(query).select(*self.param.fields,
                                             **select_params)
            else:
                self.rows = db(query).select(**select_params)

            self.number_of_pages = self.total_number_of_rows // self.param.rows_per_page
            if self.total_number_of_rows % self.param.rows_per_page > 0:
                self.number_of_pages += 1
        else:
            redirect(self.endpoint)
예제 #7
0
 def gitshow(project, commit):
     if not is_git_repo(project):
         raise HTTP(400)
     patch = run("git show " + commit, project)
     return diff2kryten(patch)