Beispiel #1
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)
Beispiel #2
0
    def process(self):
        query = None
        db = self.db
        if not self.param.search_form and self.param.search_queries:
            seach_type = safe_int(request.query.get("seach_type", 0),
                                  default=0)
            seach_string = request.query.get("seach_string")
            if seach_type < len(self.param.search_queries) and seach_string:
                query_lambda = self.param.search_queries[seach_type][1]
                try:
                    query = query_lambda(seach_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,
            )
            # 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 = False
            for field in self.param.fields:
                if field.table._tablename == pt._tablename and field.name == pt._id:
                    key_is_missing = True
            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)
Beispiel #3
0
    def __init__(
        self,
        table,
        record=None,
        readonly=False,
        deletable=True,
        noncreate=True,
        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",
        show_id=True,
        **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
        self.show_id = show_id
        # 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 self.record:
            self.vars = self._read_vars_from_record(table)
        if not readonly and request.method != "GET":
            post_vars = request.POST
            form_vars = copy.deepcopy(request.forms)
            for k in form_vars:
                self.vars[k] = form_vars[k]
            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.get(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] = value = 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()
Beispiel #4
0
def page_with_raise():
    raise HTTP(400, "oops")