Ejemplo n.º 1
0
    def create_submission(self, survey, user):
        session = object_session(survey)
        program = survey.program
        submission = model.Submission(program=program,
                                      organisation=user.organisation,
                                      survey=survey,
                                      title="First submission",
                                      approval='draft')
        session.add(submission)

        for m in program.measures:
            # Preload response type to avoid autoflush
            response_type = m.response_type
            qnode_measure = m.get_qnode_measure(survey)
            if not qnode_measure:
                continue
            response = model.Response(qnode_measure=qnode_measure,
                                      submission=submission,
                                      user=user)
            response.attachments = []
            response.not_relevant = False
            response.modified = datetime.datetime.utcnow()
            response.approval = 'final'
            response.comment = "Response for %s" % m.title
            session.add(response)
            if response_type.name == 'Yes / No':
                response.response_parts = [{'index': 1, 'note': "Yes"}]
            elif response_type.name in {
                    'Numerical', 'External Numerical', 'Planned', 'Actual'
            }:
                response.response_parts = [{'value': 1}]
            else:
                raise ValueError("Unknown response type")

            response.attachments.append(
                model.Attachment(file_name="File %s 1" % m.title,
                                 url="Bar",
                                 storage='external',
                                 organisation=user.organisation))
            response.attachments.append(
                model.Attachment(file_name="File %s 2" % m.title,
                                 url="Baz",
                                 storage='external',
                                 organisation=user.organisation))
            response.attachments.append(
                model.Attachment(file_name="File %s 3" % m.title,
                                 blob=b'A blob',
                                 storage='external',
                                 organisation=user.organisation))

        session.flush()

        calculator = Calculator.scoring(submission)
        calculator.mark_entire_survey_dirty(submission.survey)
        calculator.execute()
        submission.approval = 'final'
        session.flush()
        return submission
Ejemplo n.º 2
0
    def put(self, submission_id, measure_id, submeasure_id):
        son = self.request_son
        externals = son["externals"]
        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            response = (
                session.query(model.Response)
                .get((submission_id, measure_id)))

            if response is None:
                raise errors.MissingDocError("No such response")

            org = response.submission.organisation
            policy = user_session.policy.derive({
                'org': org,
                'surveygroups': org.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('attachment_add')

            for external in externals:
                url = external.get('url', '').strip()
                file_name = external.get('file_name', '').strip()
                if url == '' and file_name == '':
                    continue
                if url == '':
                    raise errors.ModelError(
                        "URL required for link '%s'" % file_name)
                if measure_id!=submeasure_id:        
                    attachment = model.Attachment(
                        organisation=response.submission.organisation,
                        response=response,
                        url=url,
                        file_name=file_name,
                        submeasure_id=submeasure_id,
                        storage='external'
                    )
                else:
                    attachment = model.Attachment(
                        organisation=response.submission.organisation,
                        response=response,
                        url=url,
                        file_name=file_name,
                        storage='external'
                    )                        

                session.add(attachment)
        self.get(submission_id, measure_id, submeasure_id)
Ejemplo n.º 3
0
def add_attachments(db, user_id, project_id, document_id, attachments):
    user = db.query(model.User).filter(model.User.id == user_id).first()
    if user is None:
        raise QueryException("Authentication failed")

    project, access = get_project_access(db, project_id, user_id, ACCESS_WRITE)

    document = db.query(model.Document).filter(
        (model.Document.id == document_id)
        & (model.Document.project_id == project_id)).first()
    if document is None:
        raise QueryException("Invalid document")

    # ensure existence of user specific asset dir
    root = os.path.abspath(os.path.join(config.ASSETS, user_id, "attachments"))
    if not os.path.exists(root):
        os.makedirs(root)

    # each attachment
    total_size = 0
    saved = []
    try:
        for attachment in attachments:
            # check size is ok
            item = model.Attachment(project=project,
                                    document=document,
                                    name=attachment["name"],
                                    size=attachment["size"],
                                    location="server")
            db.add(item)
            db.flush()  # get item id
            # save to filesystem
            target_filename = os.path.join(root, item.id)
            decoded = base64.b64decode(attachment["content"])
            if len(decoded) > config.MAX_ATTACHMENT_SIZE:
                raise QueryException("File too large")

            total_size += len(decoded)

            if user.category == 'free' and total_size > config.MAX_FREE_USER_STORAGE:
                raise QueryException("Quota exceeded")

            with open(target_filename, "wb") as fh:
                fh.write(decoded)
            saved.append(target_filename)
    except:
        # deal with already saved files if an exception occurs
        for filename in saved:
            os.remove(filename)
        raise

    user.storage_used += total_size
    db.commit()
Ejemplo n.º 4
0
def import_project(db, user_id, name, data, attachment_data):
    user = db.query(model.User).filter(model.User.id == user_id).first()
    if user is None:
        raise QueryException("Authentication failed")

    # for attachments
    root = os.path.abspath(os.path.join(config.ASSETS, user_id, "attachments"))
    if not os.path.exists(root):
        os.makedirs(root)

    project = model.Project(name=name, renderer='Markdown',
                            owner=user)  # renderer
    db.add(project)
    id_map = {}
    ids_added = set()
    queue = [x for x in data['documents']]
    last_added = 0
    stats = {'documents': 0, 'attachments': 0}
    while len(queue) > 0:
        item = queue.pop(0)
        if item['id'] not in id_map:
            id_map[item['id']] = model.generate_id()
        if (item['parent_id'] is None or item['parent_id']
                in ids_added) and (item['predecessor_id'] is None
                                   or item['predecessor_id'] in ids_added):
            document = model.Document(project=project,
                                      id=id_map.get(item['id']),
                                      name=item['name'],
                                      parent_id=id_map.get(item['parent_id']),
                                      predecessor_id=id_map.get(
                                          item['predecessor_id']),
                                      document_type=item['document_type'],
                                      renderer=item['renderer'],
                                      content=item['content'],
                                      updated=item['updated'],
                                      rating=item['rating'])
            db.add(document)
            stats['documents'] += 1
            ids_added.add(item['id'])
            last_added = 0
            for attachment in item['attachments']:
                new_attachment_id = model.generate_id()
                # extract and save zipped file to new id
                target_filename = os.path.join(root, new_attachment_id)
                file_data = attachment_data.open(attachment['id'], 'r').read()
                with open(target_filename, "wb") as fh:
                    fh.write(file_data)

                new_attachment = model.Attachment(id=new_attachment_id,
                                                  project=project,
                                                  document=document,
                                                  name=attachment["name"],
                                                  size=len(file_data),
                                                  location="server")
                db.add(new_attachment)

                stats['attachments'] += 1
        else:
            queue.append(item)
            last_added += 1
            if last_added > 2 * len(queue):
                raise QueryException('Circular document definition')

    db.commit()
    return stats
Ejemplo n.º 5
0
    def post(self, submission_id, measure_id,submeasure_id):
        fileinfo = self.request.files['file'][0]
        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            response = (
                session.query(model.Response)
                .get((submission_id, measure_id)))

            if response is None:
                raise errors.MissingDocError("No such response")

            org = response.submission.organisation
            policy = user_session.policy.derive({
                'org': org,
                'surveygroups': org.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('attachment_add')

            if aws.session is not None:
                s3 = aws.session.resource('s3', verify=False)
                bucket = os.environ.get('AWS_BUCKET')
                hex_key = hashlib.sha256(bytes(fileinfo['body'])).hexdigest()
                s3_path = "{0}/{1}".format(
                    response.submission.organisation_id, hex_key)

                # Metadata can not contain non-ASCII characters - so encode
                # higher Unicode characters :/
                # https://github.com/boto/boto3/issues/478#issuecomment-180608544
                file_name_enc = (
                    fileinfo["filename"]
                    .encode('ascii', errors='backslashreplace')
                    .decode('ascii')
                    [:1024])

                try:
                    s3.Bucket(bucket).put_object(
                        Key=s3_path,
                        Metadata={'filename': file_name_enc},
                        Body=bytes(fileinfo['body']))
                except botocore.exceptions.ClientError as e:
                    raise errors.InternalModelError(
                        "Failed to write to data store", log_message=str(e))



            if measure_id != submeasure_id:        
               attachment = model.Attachment(
                    organisation=response.submission.organisation,
                    response=response,
                    submeasure_id=submeasure_id,
                    file_name=fileinfo["filename"]
                )
            else:
                attachment = model.Attachment(
                    organisation=response.submission.organisation,
                    response=response,
                    file_name=fileinfo["filename"]
                )


            if aws.session is not None:
                attachment.storage = "aws"
                aws_url = aws.s3_url.format(
                    region=aws.region_name,
                    bucket=bucket,
                    s3_path=s3_path)
                attachment.url = aws_url
            else:
                attachment.storage = "database"
                attachment.blob = bytes(fileinfo['body'])
            session.add(attachment)
            session.flush()

            attachment_id = str(attachment.id)

        self.set_header("Content-Type", "text/plain")
        self.write(attachment_id)
        self.finish()
Ejemplo n.º 6
0
 def _instantiate_attachment(self, article, zendesk_attachment):
     attachment = model.Attachment(article, zendesk_attachment['file_name'])
     attachment.meta = zendesk_attachment
     return attachment