· 6 years ago · Oct 26, 2019, 10:16 PM
1import os
2import jwt
3import datetime
4from time import time
5from flask import current_app
6from flask_login import UserMixin
7from sqlalchemy.ext.declarative import declarative_base
8from werkzeug.security import generate_password_hash, check_password_hash
9
10from app import db
11from config import Constants
12
13
14rooms = db.Table('rooms',
15 db.Column('user_id', db.Integer, db.ForeignKey('user.id')),
16 db.Column('room_id', db.Integer, db.ForeignKey('room.id'))
17)
18
19
20class User(UserMixin, db.Model):
21 __searchable__ = ['body']
22
23 CONST_DEFAULT_PHOTO = '/static/images/no_photo.png'
24 id = db.Column(db.Integer, primary_key=True)
25 name = db.Column(db.String(Constants.NAME_LENGTH))
26 surname = db.Column(db.String(Constants.SURNAME_LENGTH))
27 nick = db.Column(db.String(Constants.NICK_LENGTH), unique=True)
28 age = db.Column(db.Integer)
29 address = db.Column(db.String(Constants.ADDRESS_LENGTH))
30 email = db.Column(db.String(Constants.EMAIL_LENGTH), unique=True)
31 photo = db.Column(
32 db.String(Constants.PHOTO_LENGTH),
33 default=Constants.CONST_DEFAULT_USER_PHOTO
34 )
35 about_me = db.Column(db.String(Constants.ARTICLE_LENGTH))
36 last_seen = db.Column(
37 db.DateTime, index=True,
38 default=datetime.datetime.utcnow()
39 )
40 password_hash = db.Column(db.String(256))
41
42 rooms = db.relationship(
43 'Room',
44 secondary=rooms,
45 backref=db.backref('members', lazy="dynamic")
46 )
47
48 def __init__(self, name, surname, nick, age, email):
49 self.name = name
50 self.surname = surname
51 self.nick = nick
52 self.age = age
53 self.email = email
54
55 @property
56 def status(self):
57 time_difference = datetime.datetime.utcnow() - self.last_seen
58 if time_difference.total_seconds() / 60 > 5:
59 return False
60 else:
61 return True
62
63 @staticmethod
64 def verify_reset_password_token(token):
65 try:
66 id = jwt.decode(token, current_app.config['SECRET_KEY'],
67 algorithms=['HS256'])['reset_password']
68 except:
69 return None
70 return User.query.get(id)
71
72 def get_reset_password_token(self, expires_in=Constants.TIME_OF_ACTUAL_REQUEST):
73 return jwt.encode(
74 {
75 'reset_password': self.id,
76 'exp': time() + expires_in
77 },
78 current_app.config['SECRET_KEY'],
79 algorithm='HS256'
80 ).decode('utf-8')
81
82 def from_dict(self, data):
83 pass # TODO: relize pls
84
85 def to_dict(self):
86 data = {
87 'id': self.id,
88 'name': self.name,
89 'surname': self.surname,
90 'nick': self.nick
91 }
92 return data
93
94 def set_profile_form(self, form):
95 self.name = form.name.data
96 self.surname = form.surname.data
97 self.nick = form.nick.data
98 self.age = form.age.data
99 self.email = form.email.data
100 self.address = form.address.data
101 self.upload_photo(form.photo)
102 db.session.commit()
103
104 def set_about_form(self, form):
105 self.about_me = form.about_me.data
106 db.session.commit()
107
108 def update_status(self):
109 self.last_seen = datetime.datetime.utcnow()
110 db.session.commit()
111
112 def send_message(self, text, recipient_room):
113 recipient_room.add_message(self.id, text)
114
115 def upload_photo(self, photo):
116 if photo.data:
117 filename = str(self.id) + "." + photo.data.filename.rsplit('.', 1)[1]
118
119 file_path = os.path.join(Constants.IMAGE_UPLOAD_FOLDER, filename)
120 file_path_db = os.path.join(Constants.IMAGE_DB_FOLDER, filename)
121
122 if not os.path.isdir(Constants.IMAGE_UPLOAD_FOLDER):
123 os.makedirs(Constants.IMAGE_UPLOAD_FOLDER)
124
125 photo.data.save(file_path)
126 self.photo = file_path_db
127
128 def set_password(self, password):
129 self.password_hash = generate_password_hash(password)
130 db.session.commit()
131
132 def check_password(self, password):
133 return check_password_hash(self.password_hash, password)
134
135 def commit_to_db(self):
136 db.session.add(self)
137 db.session.commit()
138
139
140class Room(db.Model):
141 id = db.Column(db.Integer, primary_key=True)
142 title = db.Column(db.String(Constants.ROOM_NAME_LENGTH))
143 photo = db.Column(
144 db.String(Constants.PHOTO_LENGTH),
145 default=Constants.CONST_DEFAULT_ROOM_PHOTO
146 )
147 is_dialog = db.Column(db.Boolean)
148
149 @staticmethod
150 def create_new_room(is_dialog=False):
151 room = Room(is_dialog=is_dialog)
152 room.commit_to_db()
153 room.create_chat()
154 return room
155
156 @staticmethod
157 def get_or_create_room(user1, user2):
158 if user1 == user2: # TODO: next time
159 return None
160
161 for room1 in user1.rooms: # FIXME: make faster
162 for room2 in user2.rooms:
163 if room1 == room2 and room1.members.count() == 2: # private
164 return room1.id
165
166 room = Room.create_new_room(is_dialog=True)
167 room.add_user(user1)
168 if user1 != user2: # Chat with yourself
169 room.add_user(user2)
170 return room.id
171
172 @property
173 def chat(self):
174 chat_name = 'chat_{}'.format(self.id)
175 chat_table = None
176
177 # If table not exists in metadata - create
178 if chat_name not in db.metadata.tables.keys():
179 chat_table = db.Table(
180 'chat_{}'.format(self.id), db.metadata,
181 db.Column('id', db.Integer, primary_key=True),
182 db.Column('text', db.String(Constants.MESSAGE_LENGTH)),
183 db.Column('sender_id', db.Integer),
184 db.Column('time', db.DateTime, index=True)
185 )
186 else:
187 chat_table = db.metadata.tables[chat_name]
188
189 return chat_table
190
191 def add_message(self, sender_id, text):
192 insert = self.chat.insert().values(
193 text=text,
194 sender_id=sender_id,
195 time=datetime.datetime.utcnow()
196 )
197 db.engine.connect().execute(insert)
198
199 @staticmethod
200 def get_message_sender(sender_id):
201 return User.query.get(sender_id)
202
203 def get_messages(self):
204 messages = db.session.query(self.chat).all()
205
206 class Message(object):
207 def __init__(self, message):
208 self.id = message[0]
209 self.text = message[1]
210 self.sender = User.query.get(message[2])
211 self.time = message[3]
212
213 messages = [Message(message)for message in messages]
214 return messages
215
216 def get_last_message(self):
217 messages = db.session.query(self.chat).all()
218 if messages:
219 return messages[-1].text
220 else:
221 return None
222
223 def create_chat(self):
224 DynamicBase = declarative_base(class_registry=dict())
225
226 class Message(DynamicBase):
227 __tablename__ = 'chat_{}'.format(self.id)
228 id = db.Column(db.Integer, primary_key=True)
229 text = db.Column(db.String(Constants.MESSAGE_LENGTH))
230 sender_id = db.Column(db.Integer)
231 time = db.Column(db.DateTime, index=True)
232
233 Message.__table__.create(db.engine)
234
235 def add_user(self, user):
236 self.members.append(user)
237 db.session.commit()
238
239 def upload_photo(self, photo):
240 if photo.data:
241 filename = str(self.id) + "." + photo.data.filename.rsplit('.', 1)[1]
242
243 file_path = os.path.join(Constants.ROOM_IMAGE_UPLOAD_FOLDER, filename)
244 file_path_db = os.path.join(Constants.ROOM_IMAGE_DB_FOLDER, filename)
245
246 if not os.path.isdir(Constants.ROOM_IMAGE_UPLOAD_FOLDER):
247 os.makedirs(Constants.ROOM_IMAGE_UPLOAD_FOLDER)
248
249 photo.data.save(file_path)
250 self.photo = file_path_db
251
252 def get_recipient(self, user):
253 if not self.is_dialog: # Chat
254 return None
255
256 for member in self.members: # Dialog
257 if user != member:
258 return member
259
260 return self.members[0] # Dialog with yourself
261
262 def get_title(self, current_user):
263 return (self.get_recipient(current_user).nick
264 if self.is_dialog
265 else self.title)
266
267 def is_member(self, user):
268 if user in self.members:
269 return True
270 else:
271 return False
272
273 def commit_to_db(self):
274 db.session.add(self)
275 db.session.commit()