# Coverage for models.py : 66%

## 101 statements 74 run 27 missing 0 excluded 7 partial

Hot-keys on this page

r m x p toggle line displays

j k next/prev highlighted chunk

0 (zero) top of page

1 (one) first highlighted chunk

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | from marshmallow import Schema, fields, pre_load from marshmallow import validate from flask_sqlalchemy import SQLAlchemy from flask_marshmallow import Marshmallow from passlib.apps import custom_app_context as password_context import re orm = SQLAlchemy() ma = Marshmallow() class ResourceAddUpdateDelete(): def add(self, resource): orm.session.add(resource) return orm.session.commit() def update(self): return orm.session.commit() def delete(self, resource): orm.session.delete(resource) return orm.session.commit() class User(orm.Model, ResourceAddUpdateDelete): id = orm.Column(orm.Integer, primary_key=True) name = orm.Column(orm.String(50), unique=True, nullable=False) # I save the hash for the password (I don't persist the actual password) password_hash = orm.Column(orm.String(120), nullable=False) creation_date = orm.Column(orm.TIMESTAMP, server_default=orm.func.current_timestamp(), nullable=False) def verify_password(self, password): return password_context.verify(password, self.password_hash) def check_password_strength_and_hash_if_ok(self, password): 37 ↛ 38 line 37 didn't jump to line 38, because the condition on line 37 was never true if len(password) < 8: return 'The password is too short. Please, specify a password with at least 8 characters.', False 39 ↛ 40 line 39 didn't jump to line 40, because the condition on line 39 was never true if len(password) > 32: return 'The password is too long. Please, specify a password with no more than 32 characters.', False 41 ↛ 42 line 41 didn't jump to line 42, because the condition on line 41 was never true if re.search(r'[A-Z]', password) is None: return 'The password must include at least one uppercase letter.', False 43 ↛ 44 line 43 didn't jump to line 44, because the condition on line 43 was never true if re.search(r'[a-z]', password) is None: return 'The password must include at least one lowercase letter.', False 45 ↛ 46 line 45 didn't jump to line 46, because the condition on line 45 was never true if re.search(r'\d', password) is None: return 'The password must include at least one number.', False 47 ↛ 48 line 47 didn't jump to line 48, because the condition on line 47 was never true if re.search(r"[ !#$%&'()*+,-./[\\\]^_`{|}~"+r'"]', password) is None: return 'The password must include at least one symbol.', False self.password_hash = password_context.hash(password) return '', True def __init__(self, name): self.name = name class Notification(orm.Model, ResourceAddUpdateDelete): id = orm.Column(orm.Integer, primary_key=True) message = orm.Column(orm.String(250), unique=True, nullable=False) ttl = orm.Column(orm.Integer, nullable=False) creation_date = orm.Column(orm.TIMESTAMP, server_default=orm.func.current_timestamp(), nullable=False) notification_category_id = orm.Column(orm.Integer, orm.ForeignKey('notification_category.id', ondelete='CASCADE'), nullable=False) notification_category = orm.relationship('NotificationCategory', backref=orm.backref('notifications', lazy='dynamic' , order_by='Notification.message')) displayed_times = orm.Column(orm.Integer, nullable=False, server_default='0') displayed_once = orm.Column(orm.Boolean, nullable=False, server_default='false') @classmethod def is_message_unique(cls, id, message): existing_notification = cls.query.filter_by(message=message).first() if existing_notification is None: return True else: if existing_notification.id == id: return True else: return False def __init__(self, message, ttl, notification_category): self.message = message self.ttl = ttl self.notification_category = notification_category class NotificationCategory(orm.Model, ResourceAddUpdateDelete): id = orm.Column(orm.Integer, primary_key=True) name = orm.Column(orm.String(150), unique=True, nullable=False) @classmethod def is_name_unique(cls, id, name): existing_notification_category = cls.query.filter_by(name=name).first() if existing_notification_category is None: return True else: 93 ↛ 94 line 93 didn't jump to line 94, because the condition on line 93 was never true if existing_notification_category.id == id: return True else: return False def __init__(self, name): self.name = name class NotificationCategorySchema(ma.Schema): id = fields.Integer(dump_only=True) # Minimum length = 3 characters name = fields.String(required=True, validate=validate.Length(3)) url = ma.URLFor('service.notificationcategoryresource', id='<id>', _external=True) notifications = fields.Nested('NotificationSchema', many=True, exclude=('notification_category',)) class NotificationSchema(ma.Schema): id = fields.Integer(dump_only=True) # Minimum length = 5 characters message = fields.String(required=True, validate=validate.Length(5)) ttl = fields.Integer() creation_date = fields.DateTime() notification_category = fields.Nested(NotificationCategorySchema, only=['id', 'url', 'name'], required=True) displayed_times = fields.Integer() displayed_once = fields.Boolean() url = ma.URLFor('service.notificationresource', id='<id>', _external=True) @pre_load def process_notification_category(self, data): notification_category = data.get('notification_category') if notification_category: if isinstance(notification_category, dict): notification_category_name = notification_category.get('name') else: notification_category_name = notification_category notification_category_dict = dict(name=notification_category_name) else: notification_category_dict = {} data['notification_category'] = notification_category_dict return data class UserSchema(ma.Schema): id = fields.Integer(dump_only=True) name = fields.String(required=True, validate=validate.Length(3)) url = ma.URLFor('service.userresource', id='<id>', _external=True)