Hide keyboard shortcuts

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 ↛ 38line 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 ↛ 40line 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 ↛ 42line 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 ↛ 44line 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 ↛ 46line 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 ↛ 48line 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 ↛ 94line 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)