class ContactTag(db.Model): """ An association between a tag and a specific contact. This allows the user to make notes about why this tag belongs on this specific contact. """ contact_id = db.Column( db.Integer, db.ForeignKey(Contact.id), primary_key=True, ) tag_id = db.Column( db.Integer, db.ForeignKey(Tag.id), primary_key=True, ) position = db.Column( db.Integer, db.Sequence('contact_tag_position'), nullable=False, ) contact = db.relationship(Contact) tag = db.relationship(Tag) note = db.Column(db.Text) @property def name(self): if self.tag: return self.tag.name @name.setter def name(self, value): if self.tag: tag = self.tag tag.name = value else: tag = Tag(name=value) if self.contact and self.contact.user: self.tag = tag_with_user(tag, self.contact.user) else: self.tag = tag @property def color(self): if self.tag: return self.tag.color def __str__(self): return self.name def __repr__(self): return "<ContactTag {contact} {tag}>".format( contact=self.contact, tag=self.tag, )
class ContactPronouns(db.Model): contact_id = db.Column( db.Integer, db.ForeignKey(Contact.id), primary_key=True, ) pronouns_id = db.Column( db.Integer, db.ForeignKey(Pronouns.id), primary_key=True, ) position = db.Column( db.Integer, db.Sequence('contact_pronouns_position'), nullable=False, ) contact = db.relationship(Contact) pronouns = db.relationship(Pronouns) def __str__(self): return str(self.pronouns) def __repr__(self): return "<ContactPronouns {cid} {pronouns}>".format( cid=self.contact_id, pronouns=self.pronouns, )
class Tag(db.Model): """ A per-user tag, used for organizing contacts. """ id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey(User.id), nullable=False) user = db.relationship(User, backref=db.backref("tags")) name = db.Column(db.String(80), nullable=False) color = db.Column(ColorType, default=random_color) __table_args__ = (db.UniqueConstraint(user_id, name), ) def __str__(self): return self.name def __repr__(self): return "<Tag {name}>".format(name=self.name)
class ContactEmail(db.Model): contact_id = db.Column( db.Integer, db.ForeignKey(Contact.id), primary_key=True, ) category = db.Column( db.String(50), primary_key=True, ) position = db.Column( db.Integer, db.Sequence('contact_email_position'), nullable=False, ) contact = db.relationship(Contact) email = db.Column(db.Text, nullable=False) def __str__(self): return self.email def __repr__(self): return "<ContactEmail {cid} {email!r} {category!r}>".format( cid=self.contact_id, email=self.email, category=self.category )
class ContactName(db.Model): contact_id = db.Column( db.Integer, db.ForeignKey(Contact.id), primary_key=True, ) category = db.Column( db.String(50), primary_key=True, ) position = db.Column( db.Integer, db.Sequence('contact_name_position'), nullable=False, ) contact = db.relationship(Contact) name = db.Column(db.Text, nullable=False) def __str__(self): return self.name def __repr__(self): return "<ContactName {cid} {category}={name!r}>".format( cid=self.contact_id, name=self.name, category=self.category )
from contactista.models import db from flask_security import (UserMixin, RoleMixin, SQLAlchemyUserDatastore) from flask_security.utils import encrypt_password, verify_password roles_users = db.Table( 'roles_users', db.Column('user_id', db.Integer(), db.ForeignKey('user.id')), db.Column('role_id', db.Integer(), db.ForeignKey('role.id'))) class Role(db.Model, RoleMixin): id = db.Column(db.Integer(), primary_key=True) name = db.Column(db.String(80), unique=True, nullable=False) description = db.Column(db.String(255)) def __str__(self): return self.name def __repr__(self): return "<Role {name}>".format(name=self.name) class User(db.Model, UserMixin): """ A person that uses this application. """ id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(255), unique=True, nullable=False, index=True)
class Contact(db.Model): """ A person in your contact book. """ id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey(User.id), nullable=False) user = db.relationship(User, backref=db.backref("contacts")) note = db.Column( db.Text, doc="Personal notes that the user made about this contact" ) # `notes_format` should probably be SQLAlchemy-Utils `ChoiceType`, # but Graphene has a bug with converting `ChoiceType`, # so this is a String instead. # https://github.com/graphql-python/graphene-sqlalchemy/issues/9 note_format = db.Column( db.String(20), default="text", doc="Markup format for notes field. One of: text, markdown" ) contact_pronouns = db.relationship( "ContactPronouns", order_by="ContactPronouns.position", collection_class=ordering_list("position"), cascade=cascade, ) pronouns_list = association_proxy( "contact_pronouns", "pronouns", creator=lambda p: ContactPronouns(pronouns=p), ) contact_names = db.relationship( "ContactName", order_by="ContactName.position", collection_class=CategoryMap, cascade=cascade, ) contact_names_list = db.relationship( "ContactName", order_by="ContactName.position", cascade=cascade, ) names = association_proxy( "contact_names", "name", creator=lambda c, n: ContactName(category=c, name=n), ) contact_emails = db.relationship( "ContactEmail", order_by="ContactEmail.position", collection_class=CategoryMap, cascade=cascade, ) contact_emails_list = db.relationship( "ContactEmail", order_by="ContactEmail.position", cascade=cascade, ) emails = association_proxy( "contact_emails", "email", creator=lambda c, e: ContactEmail(category=c, email=e), ) tags = db.relationship( "ContactTag", order_by="ContactTag.position", cascade=cascade, ) @property def pronouns(self): """ The primary set of pronouns that this contact uses. """ if not self.pronouns_list: return None return self.pronouns_list[0] @pronouns.setter def pronouns(self, value): self.pronouns_list = [value] @pronouns.deleter def pronouns(self): self.pronouns_list = [] @property def name(self): """ The primary name for this contact if it exists, or the first name in the name order if not. """ if not self.names: return None if "primary" in self.names: return self.names["primary"] # Get the first name, as ordered by the `position` column. # `self.names` is an ordered dictionary, so iteration is ordered. return next(self.names.values()) @name.setter def name(self, value): self.names["primary"] = value @property def email(self): """ The primary email for this contact if it exists, or the first email in the email order if not. """ if not self.emails: return None if "primary" in self.emails: return self.emails["primary"] # `self.emails` is an ordered dictionary, so iteration is ordered. return next(self.emails.values()) @email.setter def email(self, value): self.emails["primary"] = value def __str__(self): if self.name: return self.name return "Contact #{id}".format(id=self.id) def __repr__(self): if isinstance(self.id, int): id = self.id else: id = "unsaved" if self.names: return "<Contact {id} {name!r}>".format(id=id, name=self.name) else: return "<Contact {id}>".format(id=id)