<commit_before># coding: utf-8
#
# Portal models
#
# Copyright (C) 2016-2017 by <NAME>. <<EMAIL>>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
# For more details see the file COPYING.

from sqlalchemy import (
    select,
    Column,
    Integer,
    Boolean,
    Text,
    String,
    Date,
    DateTime,
    Time,
    ForeignKey,
    Numeric,
    Sequence,
    JSON,
    func,
    Enum,
    CheckConstraint
)

from sqlalchemy.orm import relationship, backref, object_session
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy_searchable import make_searchable
from sqlalchemy_utils.types import TSVectorType, URLType, EmailType

from ekklesia_portal.database import Base, integer_pk, C
from ekklesia_portal.enums import ArgumentType, EkklesiaUserType, Majority, PropositionStatus, SupporterStatus, VotingType, VotingStatus, VotingSystem
from ekklesia_portal.helper.utils import cached_property


make_searchable(Base.metadata, options={'regconfig': 'pg_catalog.german'})


class Group(Base):
    __tablename__ = 'groups'
    id = Column(Integer, Sequence('id_seq', optional=True), primary_key=True)
    name = Column(String(64), unique=True, nullable=False)
    is_admin_group = Column(Boolean, nullable=False, server_default='false')
    members = association_proxy('group_members', 'member')  # <-GroupMember-> User


class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, Sequence('id_seq', optional=True), primary_key=True)
    name = Column(String(64), unique=True, nullable=False)
    email = Column(EmailType, unique=True, comment='optional, for notifications, otherwise use user/mails/')
    auth_type = Column(String(8), nullable=False, server_default='system', comment='deleted,system,token,virtual,oauth(has UserProfile)')
    joined = Column(DateTime, nullable=False, server_default=func.now())
    active = Column(Boolean, nullable=False, server_default='true')
    last_active = Column(DateTime, nullable=False, server_default=func.now(),
                         comment='last relevant activity (to be considered active member §2.2)')
    # actions: submit/support proposition, voting, or explicit, deactivate after 2 periods
    profile = relationship("UserProfile", uselist=False, back_populates="user")
    groups = association_proxy('member_groups', 'group')  # <-GroupMember-> Group
    # from user/membership/ all_nested_groups
    departments = association_proxy('member_departments', 'department')  # <-DepartmentMember-> Department
    areas = association_proxy('member_areas', 'area')  # <-AreaMember-> SubjectArea
    supports = association_proxy('member_propositions', 'proposition')  # <-Supporter-> Proposition
    arguments = relationship("Argument", back_populates="author")
    secret_voters = association_proxy('member_secretvoters', 'secretvoter')  # <-SecretVoter-> Ballot
    urns = association_proxy('member_urns', 'urn')  # <-UrnSupporter-> Urn
    postal_votes = association_proxy('member_postal', 'voting')  # <-PostalVote-> VotingPhase

    @property
    def managed_departments(self):
        return [md.department for md in self.member_departments if md.is_admin]


class UserPassword(Base):<commit_msg>User.can_login_until<commit_after># coding: utf-8
#
# Portal models
#
# Copyright (C) 2016-2017 by <NAME>. <<EMAIL>>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
# For more details see the file COPYING.

from sqlalchemy import (
    select,
    Column,
    Integer,
    Boolean,
    Text,
    String,
    Date,
    DateTime,
    Time,
    ForeignKey,
    Numeric,
    Sequence,
    JSON,
    func,
    Enum,
    CheckConstraint
)

from sqlalchemy.orm import relationship, backref, object_session
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy_searchable import make_searchable
from sqlalchemy_utils.types import TSVectorType, URLType, EmailType

from ekklesia_portal.database import Base, integer_pk, C
from ekklesia_portal.enums import ArgumentType, EkklesiaUserType, Majority, PropositionStatus, SupporterStatus, VotingType, VotingStatus, VotingSystem
from ekklesia_portal.helper.utils import cached_property


make_searchable(Base.metadata, options={'regconfig': 'pg_catalog.german'})


class Group(Base):
    __tablename__ = 'groups'
    id = Column(Integer, Sequence('id_seq', optional=True), primary_key=True)
    name = Column(String(64), unique=True, nullable=False)
    is_admin_group = Column(Boolean, nullable=False, server_default='false')
    members = association_proxy('group_members', 'member')  # <-GroupMember-> User


class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, Sequence('id_seq', optional=True), primary_key=True)
    name = Column(String(64), unique=True, nullable=False)
    email = Column(EmailType, unique=True, comment='optional, for notifications, otherwise use user/mails/')
    auth_type = Column(String(8), nullable=False, server_default='system', comment='deleted,system,token,virtual,oauth(has UserProfile)')
    joined = Column(DateTime, nullable=False, server_default=func.now())
    active = Column(Boolean, nullable=False, server_default='true')
    last_active = Column(DateTime, nullable=False, server_default=func.now(),
                         comment='last relevant activity (to be considered active member §2.2)')
    can_login_until = C(DateTime, comment='optional expiration datetime after which login is no longer possible')
    # actions: submit/support proposition, voting, or explicit, deactivate after 2 periods
    profile = relationship("UserProfile", uselist=False, back_populates="user")
    groups = association_proxy('member_groups', 'group')  # <-GroupMember-> Group
    # from user/membership/ all_nested_groups
    departments = association_proxy('member_departments', 'department')  # <-DepartmentMember-> Department
    areas = association_proxy('member_areas', 'area')  # <-AreaMember-> SubjectArea
    supports = association_proxy('member_propositions', 'proposition')  # <-Supporter-> Proposition
    arguments = relationship("Argument", back_populates="author")
    secret_voters = association_proxy('member_secretvoters', 'secretvoter')  # <-SecretVoter-> Ballot
    urns = association_proxy('member_urns', 'urn')  # <-UrnSupporter-> Urn
    postal_votes = association_proxy('member_postal', 'voting')  # <-PostalVote-> VotingPhase

    @property
    def managed_departments(self):
        return [md.department for md in self.member_departments if md.is_admin]


class UserPassword(Base):
{'fraction_non_alphanumeric': 0.10067714322217963, 'fraction_numerical': 0.0045994633959371405, 'mean_word_length': 4.890142964635064, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6528557', 'n_tokens_mistral': 2289, 'n_tokens_neox': 2209, 'n_words': 663}