class Disbursement(ModelBase):
    __tablename__ = 'disbursement'

    creator_user_id = db.Column(db.Integer, db.ForeignKey('user.id'), index=True)

    label = db.Column(db.String)
    search_string = db.Column(db.String)
    search_filter_params = db.Column(db.String)
    include_accounts = db.Column(db.ARRAY(db.Integer))
    exclude_accounts = db.Column(db.ARRAY(db.Integer))
    state = db.Column(db.String)
    transfer_type = db.Column(db.String)
    _disbursement_amount_wei = db.Column(db.Numeric(27), default=0)

    creator_user = db.relationship('User',
                                    primaryjoin='User.id == Disbursement.creator_user_id')

    transfer_accounts = db.relationship(
        "TransferAccount",
        secondary=disbursement_transfer_account_association_table,
        back_populates="disbursements")

    credit_transfers = db.relationship(
        "CreditTransfer",
        secondary=disbursement_credit_transfer_association_table,
        back_populates="disbursement")

    @hybrid_property
    def disbursement_amount(self):
        return (self._disbursement_amount_wei or 0) / int(1e16)

    @disbursement_amount.setter
    def disbursement_amount(self, val):
        self._disbursement_amount_wei = val * int(1e16)

    def _transition_state(self, new_state):
        if new_state not in ALLOWED_STATES:
            raise Exception(f'{new_state} is not an allowed state, must be one of f{ALLOWED_STATES}')

        allowed_transitions = ALLOWED_STATE_TRANSITIONS.get(self.state, [])

        if new_state not in allowed_transitions:
            raise Exception(f'{new_state} is not an allowed transition, must be one of f{allowed_transitions}')

        self.state = new_state

    def approve(self):
        self._transition_state('APPROVED')

    def reject(self):
        self._transition_state('REJECTED')

    def __init__(self, *args, **kwargs):

        super(Disbursement, self).__init__(*args, **kwargs)

        self.state = 'PENDING'
Beispiel #2
0
class Notes(db.Model):
    id = db.Column(db.Integer,primary_key=True)
    title= db.Column(db.String(100), unique=False)
    body = db.Column(db.Text, unique=False)
    labels= db.relationship('Label',secondary=notes_label,backref='labels')
    label = db.Column(db.ARRAY(db.Integer),nullable=True)
    user_id = db.Column(db.Integer,db.ForeignKey('user.id'),nullable=False)
    
    def __init__(self,title,body,label,user_id):
        self.title=title
        self.body=body
        self.label=label
        self.user_id=user_id
Beispiel #3
0
class Projects(db.Model):
    project_id = db.Column(db.String(36), primary_key=True)
    owner_id = db.Column(db.String(36))
    project_name = db.Column(db.Text)
    sources = db.Column(db.ARRAY(db.String))
    citation_type = db.Column(db.Text)

    def __init__(  # pylint: disable=too-many-arguments
        self,
        project_id: str,
        owner_id: str,
        project_name: str,
        sources: list,
        citation_type: CitationType = CitationType.MLA,
    ):
        self.project_id = project_id
        self.owner_id = owner_id
        self.project_name = project_name
        self.sources = []
        self.sources.extend(sources)
        self.citation_type = citation_type.value

    def __repr__(self):
        return "Project(project_id={}, owner_id={}, project_name={}, sources={}, citation_type={})".format(  # pylint: disable = line-too-long
            self.project_id,
            self.owner_id,
            self.project_name,
            self.sources,
            self.citation_type,
        )

    def json(self) -> dict:
        data = {
            "project_id": self.project_id,
            "owner_id": self.owner_id,
            "project_name": self.project_name,
            "sources": self.sources,
            "citation_type": self.citation_type,
        }
        return data
Beispiel #4
0
class Disbursement(ModelBase, OneOrgBase):
    __tablename__ = 'disbursement'

    creator_user_id = db.Column(db.Integer,
                                db.ForeignKey('user.id'),
                                index=True)

    label = db.Column(db.String)
    notes = db.Column(db.String(), default='')
    errors = db.Column(db.ARRAY(db.String), default=[])
    search_string = db.Column(db.String)
    search_filter_params = db.Column(db.String)
    include_accounts = db.Column(db.ARRAY(db.Integer))
    exclude_accounts = db.Column(db.ARRAY(db.Integer))
    state = db.Column(db.String)
    transfer_type = db.Column(db.String)
    _disbursement_amount_wei = db.Column(db.Numeric(27), default=0)

    creator_user = db.relationship(
        'User',
        primaryjoin='User.id == Disbursement.creator_user_id',
        lazy=True)

    transfer_accounts = db.relationship(
        "TransferAccount",
        secondary=disbursement_transfer_account_association_table,
        back_populates="disbursements",
        lazy=True)

    credit_transfers = db.relationship(
        "CreditTransfer",
        secondary=disbursement_credit_transfer_association_table,
        back_populates="disbursement",
        lazy=True)

    approvers = db.relationship(
        "User",
        secondary=disbursement_approver_user_association_table,
        lazy=True)
    approval_times = db.Column(db.ARRAY(db.DateTime), default=[])

    @hybrid_property
    def recipient_count(self):
        return db.session.query(func.count(disbursement_transfer_account_association_table.c.disbursement_id))\
            .filter(disbursement_transfer_account_association_table.c.disbursement_id==self.id).first()[0]

    @hybrid_property
    def total_disbursement_amount(self):
        return self.recipient_count * self.disbursement_amount

    @hybrid_property
    def disbursement_amount(self):
        return (self._disbursement_amount_wei or 0) / int(1e16)

    @disbursement_amount.setter
    def disbursement_amount(self, val):
        self._disbursement_amount_wei = val * int(1e16)

    def _transition_state(self, new_state):
        if new_state not in ALLOWED_STATES:
            raise Exception(
                f'{new_state} is not an allowed state, must be one of f{ALLOWED_STATES}'
            )

        allowed_transitions = ALLOWED_STATE_TRANSITIONS.get(self.state, [])

        if new_state not in allowed_transitions:
            raise Exception(
                f'{new_state} is not an allowed transition, must be one of f{allowed_transitions}'
            )

        self.state = new_state

    def add_approver(self):
        if g.user not in self.approvers:
            if not self.approval_times:
                self.approval_times = []
            if len(self.approvers) == len(self.approval_times):
                self.approval_times = self.approval_times + [
                    datetime.datetime.utcnow()
                ]
            self.approvers.append(g.user)

    def check_if_approved(self):
        if AccessControl.has_sufficient_tier(g.user.roles, 'ADMIN',
                                             'sempoadmin'):
            return True
        if current_app.config['REQUIRE_MULTIPLE_APPROVALS']:
            # It always has to be approved by at least two people
            if len(self.approvers) <= 1:
                return False
            # If there's an `ALLOWED_APPROVERS` list, one of the approvers has to be in it
            if current_app.config['ALLOWED_APPROVERS']:
                # approve if email in list
                for user in self.approvers:
                    if user.email in current_app.config['ALLOWED_APPROVERS']:
                        return True
            # If there's not an `ALLOWED_APPROVERS` list, it just has to be approved by more than one person
            else:
                return True
        else:
            # Multi-approval is off, so it's approved by default
            return True

    def approve(self):
        self.add_approver()
        if self.check_if_approved():
            self._transition_state(APPROVED)
        else:
            self._transition_state(PARTIAL)
            return PARTIAL

    def reject(self):
        self.add_approver()
        self._transition_state(REJECTED)

    def __init__(self, *args, **kwargs):
        self.organisation_id = g.active_organisation.id
        super(Disbursement, self).__init__(*args, **kwargs)
        self.state = PENDING
class User(db.Model):
    """ Describes the history associated with a task """
    __tablename__ = "users"

    id = db.Column(db.BigInteger, primary_key=True, index=True)
    validation_message = db.Column(db.Boolean, default=True, nullable=False)
    username = db.Column(db.String, unique=True)
    role = db.Column(db.Integer, default=0, nullable=False)
    mapping_level = db.Column(db.Integer, default=1, nullable=False)
    tasks_mapped = db.Column(db.Integer, default=0, nullable=False)
    tasks_validated = db.Column(db.Integer, default=0, nullable=False)
    tasks_invalidated = db.Column(db.Integer, default=0, nullable=False)
    projects_mapped = db.Column(db.ARRAY(db.Integer))
    email_address = db.Column(db.String)
    is_email_verified = db.Column(db.Boolean, default=False)
    is_expert = db.Column(db.Boolean, default=False)
    twitter_id = db.Column(db.String)
    facebook_id = db.Column(db.String)
    linkedin_id = db.Column(db.String)
    date_registered = db.Column(db.DateTime, default=timestamp)
    # Represents the date the user last had one of their tasks validated
    last_validation_date = db.Column(db.DateTime, default=timestamp)

    # Relationships
    accepted_licenses = db.relationship("License",
                                        secondary=users_licenses_table)

    def create(self):
        """ Creates and saves the current model to the DB """
        db.session.add(self)
        db.session.commit()

    def save(self):
        db.session.commit()

    def get_by_id(self, user_id: int):
        """ Return the user for the specified id, or None if not found """
        return User.query.get(user_id)

    def get_by_username(self, username: str):
        """ Return the user for the specified username, or None if not found """
        return User.query.filter_by(username=username).one_or_none()

    def update_username(self, username: str):
        """ Update the username """
        self.username = username
        db.session.commit()

    def update(self, user_dto: UserDTO):
        """ Update the user details """
        self.email_address = user_dto.email_address.lower(
        ) if user_dto.email_address else None
        self.twitter_id = user_dto.twitter_id.lower(
        ) if user_dto.twitter_id else None
        self.facebook_id = user_dto.facebook_id.lower(
        ) if user_dto.facebook_id else None
        self.linkedin_id = user_dto.linkedin_id.lower(
        ) if user_dto.linkedin_id else None
        self.validation_message = user_dto.validation_message
        db.session.commit()

    def set_email_verified_status(self, is_verified: bool):
        """ Updates email verfied flag on successfully verified emails"""
        self.is_email_verified = is_verified
        db.session.commit()

    def set_is_expert(self, is_expert: bool):
        """ Enables or disables expert mode on the user"""
        self.is_expert = is_expert
        db.session.commit()

    @staticmethod
    def get_all_users(query: UserSearchQuery) -> UserSearchDTO:
        """ Search and filter all users """

        # Base query that applies to all searches
        base = db.session.query(User.id, User.username, User.mapping_level,
                                User.role)

        # Add filter to query as required
        if query.mapping_level:
            base = base.filter(User.mapping_level == MappingLevel[
                query.mapping_level.upper()].value)
        if query.username:
            base = base.filter(
                User.username.ilike(query.username.lower() + '%'))
        if query.role:
            base = base.filter(User.role == UserRole[query.role.upper()].value)

        results = base.order_by(User.username).paginate(query.page, 20, True)

        dto = UserSearchDTO()
        for result in results.items:
            listed_user = ListedUser()
            listed_user.id = result.id
            listed_user.mapping_level = MappingLevel(result.mapping_level).name
            listed_user.username = result.username
            listed_user.role = UserRole(result.role).name

            dto.users.append(listed_user)

        dto.pagination = Pagination(results)
        return dto

    @staticmethod
    def get_all_users_not_pagainated():
        """ Get all users in DB"""
        return db.session.query(User.id).all()

    @staticmethod
    def filter_users(user_filter: str, project_id: int,
                     page: int) -> UserFilterDTO:
        """ Finds users that matches first characters, for auto-complete.

        Users who have participated (mapped or validated) in the project, if given, will be
        returned ahead of those who have not.
        """
        # Note that the projects_mapped column includes both mapped and validated projects.
        results = db.session.query(User.username, User.projects_mapped.any(project_id).label("participant")) \
            .filter(User.username.ilike(user_filter.lower() + '%')) \
            .order_by(desc("participant").nullslast(), User.username).paginate(page, 20, True)
        if results.total == 0:
            raise NotFound()

        dto = UserFilterDTO()
        for result in results.items:
            dto.usernames.append(result.username)
            if project_id is not None:
                participant = ProjectParticipantUser()
                participant.username = result.username
                participant.project_id = project_id
                participant.is_participant = bool(result.participant)
                dto.users.append(participant)

        dto.pagination = Pagination(results)
        return dto

    @staticmethod
    def upsert_mapped_projects(user_id: int, project_id: int):
        """ Adds projects to mapped_projects if it doesn't exist """
        sql = "select * from users where id = {0} and projects_mapped @> '{{{1}}}'".format(
            user_id, project_id)
        result = db.engine.execute(sql)

        if result.rowcount > 0:
            return  # User has previously mapped this project so return

        sql = '''update users
                    set projects_mapped = array_append(projects_mapped, {0})
                  where id = {1}'''.format(project_id, user_id)

        db.engine.execute(sql)

    @staticmethod
    def get_mapped_projects(user_id: int,
                            preferred_locale: str) -> UserMappedProjectsDTO:
        """ Get all projects a user has mapped on """

        # This query looks scary, but we're really just creating an outer join between the query that gets the
        # counts of all mapped tasks and the query that gets counts of all validated tasks.  This is necessary to
        # handle cases where users have only validated tasks on a project, or only mapped on a project.
        sql = '''SELECT p.id,
                        p.status,
                        p.default_locale,
                        c.mapped,
                        c.validated,
                        st_asgeojson(p.centroid)
                   FROM projects p,
                        (SELECT coalesce(v.project_id, m.project_id) project_id,
                                coalesce(v.validated, 0) validated,
                                coalesce(m.mapped, 0) mapped
                          FROM (SELECT t.project_id,
                                       count (t.validated_by) validated
                                  FROM tasks t
                                 WHERE t.project_id IN (SELECT unnest(projects_mapped) FROM users WHERE id = {0})
                                   AND t.validated_by = {0}
                                 GROUP BY t.project_id, t.validated_by) v
                         FULL OUTER JOIN
                        (SELECT t.project_id,
                                count(t.mapped_by) mapped
                           FROM tasks t
                          WHERE t.project_id IN (SELECT unnest(projects_mapped) FROM users WHERE id = {0})
                            AND t.mapped_by = {0}
                          GROUP BY t.project_id, t.mapped_by) m
                         ON v.project_id = m.project_id) c
                   WHERE p.id = c.project_id ORDER BY p.id DESC'''.format(
            user_id)

        results = db.engine.execute(sql)

        if results.rowcount == 0:
            raise NotFound()

        mapped_projects_dto = UserMappedProjectsDTO()
        for row in results:
            mapped_project = MappedProject()
            mapped_project.project_id = row[0]
            mapped_project.status = ProjectStatus(row[1]).name
            mapped_project.tasks_mapped = row[3]
            mapped_project.tasks_validated = row[4]
            mapped_project.centroid = geojson.loads(row[5])

            project_info = ProjectInfo.get_dto_for_locale(
                row[0], preferred_locale, row[2])
            mapped_project.name = project_info.name

            mapped_projects_dto.mapped_projects.append(mapped_project)

        return mapped_projects_dto

    def set_user_role(self, role: UserRole):
        """ Sets the supplied role on the user """
        self.role = role.value
        db.session.commit()

    def set_mapping_level(self, level: MappingLevel):
        """ Sets the supplied level on the user """
        self.mapping_level = level.value
        db.session.commit()

    def accept_license_terms(self, license_id: int):
        """ Associate the user in scope with the supplied license """
        image_license = License.get_by_id(license_id)
        self.accepted_licenses.append(image_license)
        db.session.commit()

    def has_user_accepted_licence(self, license_id: int):
        """ Test to see if the user has accepted the terms of the specified license"""
        image_license = License.get_by_id(license_id)

        if image_license in self.accepted_licenses:
            return True

        return False

    def delete(self):
        """ Delete the user in scope from DB """
        db.session.delete(self)
        db.session.commit()

    def as_dto(self, logged_in_username: str) -> UserDTO:
        """ Create DTO object from user in scope """
        user_dto = UserDTO()
        user_dto.id = self.id
        user_dto.username = self.username
        user_dto.role = UserRole(self.role).name
        user_dto.mapping_level = MappingLevel(self.mapping_level).name
        user_dto.is_expert = self.is_expert or False
        user_dto.tasks_mapped = self.tasks_mapped
        user_dto.tasks_validated = self.tasks_validated
        user_dto.tasks_invalidated = self.tasks_invalidated
        user_dto.twitter_id = self.twitter_id
        user_dto.linkedin_id = self.linkedin_id
        user_dto.facebook_id = self.facebook_id
        user_dto.validation_message = self.validation_message

        if self.username == logged_in_username:
            # Only return email address when logged in user is looking at their own profile
            user_dto.email_address = self.email_address
            user_dto.is_email_verified = self.is_email_verified

        return user_dto
Beispiel #6
0
class User(db.Model):
    """ Describes the history associated with a task """
    __tablename__ = "users"

    id = db.Column(db.BigInteger, primary_key=True, index=True)
    username = db.Column(db.String, unique=True)
    role = db.Column(db.Integer, default=0, nullable=False)
    mapping_level = db.Column(db.Integer, default=1, nullable=False)
    tasks_mapped = db.Column(db.Integer, default=0, nullable=False)
    tasks_validated = db.Column(db.Integer, default=0, nullable=False)
    tasks_invalidated = db.Column(db.Integer, default=0, nullable=False)
    projects_mapped = db.Column(db.ARRAY(db.Integer))
    email_address = db.Column(db.String)
    is_email_verified = db.Column(db.Boolean, default=False)
    twitter_id = db.Column(db.String)
    facebook_id = db.Column(db.String)
    linkedin_id = db.Column(db.String)
    date_registered = db.Column(db.DateTime, default=timestamp)
    # Represents the date the user last had one of their tasks validated
    last_validation_date = db.Column(db.DateTime, default=timestamp)

    # Relationships
    accepted_licenses = db.relationship("License",
                                        secondary=users_licenses_table)

    def create(self):
        """ Creates and saves the current model to the DB """
        db.session.add(self)
        db.session.commit()

    def save(self):
        db.session.commit()

    def get_by_id(self, user_id: int):
        """ Return the user for the specified id, or None if not found """
        return User.query.get(user_id)

    def get_by_username(self, username: str):
        """ Return the user for the specified username, or None if not found """
        return User.query.filter_by(username=username).one_or_none()

    def update_username(self, username: str):
        """ Update the username """
        self.username = username
        db.session.commit()

    def update(self, user_dto: UserDTO):
        """ Update the user details """
        self.email_address = user_dto.email_address.lower(
        ) if user_dto.email_address else None
        self.twitter_id = user_dto.twitter_id.lower(
        ) if user_dto.twitter_id else None
        self.facebook_id = user_dto.facebook_id.lower(
        ) if user_dto.facebook_id else None
        self.linkedin_id = user_dto.linkedin_id.lower(
        ) if user_dto.linkedin_id else None
        db.session.commit()

    def set_email_verified_status(self, is_verified: bool):
        """ Updates email verfied flag on successfully verified emails"""
        self.is_email_verified = is_verified
        db.session.commit()

    @staticmethod
    def get_all_users(query: UserSearchQuery) -> UserSearchDTO:
        """ Search and filter all users """

        # Base query that applies to all searches
        base = db.session.query(User.id, User.username, User.mapping_level,
                                User.role)

        # Add filter to query as required
        if query.mapping_level:
            base = base.filter(User.mapping_level == MappingLevel[
                query.mapping_level.upper()].value)
        if query.username:
            base = base.filter(
                User.username.ilike(query.username.lower() + '%'))
        if query.role:
            base = base.filter(User.role == UserRole[query.role.upper()].value)

        results = base.order_by(User.username).paginate(query.page, 20, True)

        dto = UserSearchDTO()
        for result in results.items:
            listed_user = ListedUser()
            listed_user.id = result.id
            listed_user.mapping_level = MappingLevel(result.mapping_level).name
            listed_user.username = result.username
            listed_user.role = UserRole(result.role).name

            dto.users.append(listed_user)

        dto.pagination = Pagination(results)
        return dto

    @staticmethod
    def get_all_users_not_pagainated():
        """ Get all users in DB"""
        return db.session.query(User.id).all()

    @staticmethod
    def filter_users(user_filter: str, page: int) -> UserFilterDTO:
        """ Finds users that matches first characters, for auto-complete """
        results = db.session.query(User.username).filter(User.username.ilike(user_filter.lower() + '%')) \
            .order_by(User.username).paginate(page, 20, True)

        if results.total == 0:
            raise NotFound()

        dto = UserFilterDTO()
        for result in results.items:
            dto.usernames.append(result.username)

        dto.pagination = Pagination(results)
        return dto

    @staticmethod
    def upsert_mapped_projects(user_id: int, project_id: int):
        """ Adds projects to mapped_projects if it doesn't exist """
        sql = "select * from users where id = {0} and projects_mapped @> '{{{1}}}'".format(
            user_id, project_id)
        result = db.engine.execute(sql)

        if result.rowcount > 0:
            return  # User has previously mapped this project so return

        sql = '''update users
                    set projects_mapped = array_append(projects_mapped, {0})
                  where id = {1}'''.format(project_id, user_id)

        db.engine.execute(sql)

    @staticmethod
    def get_mapped_projects(user_id: int,
                            preferred_locale: str) -> UserMappedProjectsDTO:
        """ Get all projects a user has mapped on """
        sql = '''select p.id, p.status, p.default_locale, count(t.mapped_by), count(t.validated_by), st_asgeojson(p.centroid),
                        st_asgeojson(p.geometry)
                   from projects p,
                        tasks t
                  where p.id in (select unnest(projects_mapped) from users where id = {0})
                    and p.id = t.project_id
                    and (t.mapped_by = {0} or t.mapped_by is null)
                    and (t.validated_by = {0} or t.validated_by is null)
               GROUP BY p.id, p.status, p.centroid, p.geometry'''.format(
            user_id)

        results = db.engine.execute(sql)

        if results.rowcount == 0:
            raise NotFound()

        mapped_projects_dto = UserMappedProjectsDTO()
        for row in results:
            mapped_project = MappedProject()
            mapped_project.project_id = row[0]
            mapped_project.status = ProjectStatus(row[1]).name
            mapped_project.tasks_mapped = row[3]
            mapped_project.tasks_validated = row[4]
            mapped_project.centroid = geojson.loads(row[5])
            mapped_project.aoi = geojson.loads(row[6])

            project_info = ProjectInfo.get_dto_for_locale(
                row[0], preferred_locale, row[2])
            mapped_project.name = project_info.name

            mapped_projects_dto.mapped_projects.append(mapped_project)

        return mapped_projects_dto

    def set_user_role(self, role: UserRole):
        """ Sets the supplied role on the user """
        self.role = role.value
        db.session.commit()

    def set_mapping_level(self, level: MappingLevel):
        """ Sets the supplied level on the user """
        self.mapping_level = level.value
        db.session.commit()

    def accept_license_terms(self, license_id: int):
        """ Associate the user in scope with the supplied license """
        image_license = License.get_by_id(license_id)
        self.accepted_licenses.append(image_license)
        db.session.commit()

    def has_user_accepted_licence(self, license_id: int):
        """ Test to see if the user has accepted the terms of the specified license"""
        image_license = License.get_by_id(license_id)

        if image_license in self.accepted_licenses:
            return True

        return False

    def delete(self):
        """ Delete the user in scope from DB """
        db.session.delete(self)
        db.session.commit()

    def as_dto(self, logged_in_username: str) -> UserDTO:
        """ Create DTO object from user in scope """
        user_dto = UserDTO()
        user_dto.id = self.id
        user_dto.username = self.username
        user_dto.role = UserRole(self.role).name
        user_dto.mapping_level = MappingLevel(self.mapping_level).name
        user_dto.tasks_mapped = self.tasks_mapped
        user_dto.tasks_validated = self.tasks_validated
        user_dto.twitter_id = self.twitter_id
        user_dto.linkedin_id = self.linkedin_id
        user_dto.facebook_id = self.facebook_id

        if self.username == logged_in_username:
            # Only return email address when logged in user is looking at their own profile
            user_dto.email_address = self.email_address
            user_dto.is_email_verified = self.is_email_verified

        return user_dto