# Planète Casio v5
# models.priv: Database models for groups and privilege management

from app import db

# Privileges are represented by strings (slugs), for instance "post-news" or
# "delete-own-posts". Belonging to a group automatically grants a user the
# privileges of that group; additionally, administrators (or any people with
# the "grant-special-privileges" privilege) can grant privileges on a per-user
# basis.


# SpecialPrivilege: Privilege manually granted to a user
class SpecialPrivilege(db.Model):
    __tablename__ = 'special_privilege'
    id = db.Column(db.Integer, primary_key=True)

    # Member that is granted the privilege
    member_id = db.Column(db.Integer, db.ForeignKey('member.id'), index=True)
    member = db.relationship('Member', back_populates="special_privs",
        foreign_keys=member_id)
    # Privilege name
    priv = db.Column(db.String(64))

    def __init__(self, member, priv):
        self.member = member
        self.priv = priv

    def __repr__(self):
        return f'<Privilege: {self.priv} of member #{self.member_id}>'


# Group: User group, corresponds to a community role and a set of privileges
class Group(db.Model):
    __tablename__ = 'group'

    # Unique group ID
    id = db.Column(db.Integer, primary_key=True)
    # Full name, such as "Administrateur" or "Membre d'honneur".
    name = db.Column(db.Unicode(50), unique=True)
    # The CSS code should not assume any specific layout and typically applies
    # to a text node. Use attributes like color, font-style, font-weight, etc.
    css = db.Column(db.UnicodeText)
    # Textual description
    description = db.Column(db.UnicodeText)
    # List of members (lambda delays evaluation)
    members = db.relationship('Member', secondary=lambda: GroupMember,
        back_populates='groups', lazy='joined')
    # List of privileges
    privileges = db.relationship('GroupPrivilege', back_populates='group')

    def __init__(self, name, css, descr):
        self.name = name
        self.css = css
        self.description = descr
        self.members = []

    def delete(self):
        """
        Deletes the group and the associated information:
        * Group privileges
        """

        for gp in self.privileges:
            db.session.delete(gp)
        db.session.commit()

        db.session.delete(self)
        db.session.commit()

    def privs(self):
        return sorted(gp.priv for gp in self.privileges)

    def __repr__(self):
        return f'<Group: {self.name}>'


# Many-to-many relation for users belonging to groups
GroupMember = db.Table('group_member', db.Model.metadata,
    db.Column('gid', db.Integer, db.ForeignKey('group.id')),
    db.Column('uid', db.Integer, db.ForeignKey('member.id')))

# GroupPrivilege: A list of privileges for groups, materialized as a table
class GroupPrivilege(db.Model):
    __tablename__ = 'group_privilege'
    id = db.Column(db.Integer, primary_key=True)

    group_id = db.Column(db.Integer, db.ForeignKey('group.id'))
    group = db.relationship('Group', back_populates='privileges',
        foreign_keys=group_id)

    priv = db.Column(db.String(64))

    def __init__(self, group, priv):
        self.group = group
        self.priv = priv
