Completed
Push — master ( 5e3fd7...30a0be )
by Andrew
28s
created

Room.__unicode__()   A

Complexity

Conditions 1

Size

Total Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
c 1
b 0
f 0
dl 0
loc 2
rs 10
1
import datetime
2
import json
3
import time
4
from enum import Enum
5
from time import mktime
6
7
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser
8
from django.db import models
9
from django.db.models import CharField, DateField, FileField, BooleanField, URLField
10
11
from chat.log_filters import id_generator
12
from chat.settings import GENDERS, DEFAULT_PROFILE_ID, JS_CONSOLE_LOGS
13
14
15
def get_random_path(instance, filename):
16
	"""
17
	:param filename base string for generated name
18
	:return: a unique string filename
19
	"""
20
	return "{}_{}".format(id_generator(8), filename)
21
22
23
class User(AbstractBaseUser):
24
	def get_short_name(self):
25
		return self.username
26
27
	def get_full_name(self):
28
		return self.username
29
30
	@property
31
	def is_staff(self):
32
		# every registered user can edit database
33
		return self.pk == DEFAULT_PROFILE_ID
34
35
	def has_perm(self, perm, obj=None):
36
		return self.is_staff
37
38
	def has_perms(self, perm, obj=None):
39
		return True
40
41
	def has_module_perms(self, app_label):
42
		return self.is_staff
43
44
	USERNAME_FIELD = 'username'
45
	username = CharField(max_length=30, null=False, unique=True)
46
47
	# specifies auth, create email, etc methods
48
	objects = BaseUserManager()
49
50
	# ISO/IEC 5218 1 male, 2 - female
51
	sex = models.SmallIntegerField(null=False, default=0)
52
53
	@property
54
	def sex_str(self):
55
		return GENDERS[self.sex]
56
57
	@sex_str.setter
58
	def sex_str(self, sex):
59
		if sex == 'Male':
60
			self.sex = 1
61
		elif sex == 'Female':
62
			self.sex = 2
63
		else:
64
			self.sex = 0
65
66
67
class Subscription(models.Model):
68
	user = models.ForeignKey(User, null=False)
69
	inactive = BooleanField(default=False, null=False)
70
	registration_id = models.CharField(null=False, max_length=191, unique=True)
71
	created = models.DateTimeField(default=datetime.datetime.now)
72
	updated = models.DateTimeField(default=datetime.datetime.now)
73
	agent = models.CharField(max_length=64, null=True, blank=True)
74
	is_mobile = BooleanField(default=False, null=False, blank=True)
75
	ip = models.ForeignKey('IpAddress', null=True, blank=True)
76
77
	def __unicode__(self):
78
		return self.__str__()
79
80
	def __str__(self):
81
		return str(self.id)
82
83
84
class Verification(models.Model):
85
86
	class TypeChoices(Enum):
87
		register = 'r'
88
		password = 'p'
89
90
	# a - account activation, r - recover
91
	type = models.CharField(null=False, max_length=1)
92
	token = models.CharField(max_length=17, null=False, default=id_generator)
93
	user = models.ForeignKey(User, null=False)
94
	time = models.DateTimeField(default=datetime.datetime.now)
95
	verified = BooleanField(default=False)
96
97
	def __unicode__(self):
98
		return self.__str__()
99
100
	def __str__(self):
101
		return str(self.id)
102
103
	@property
104
	def type_enum(self):
105
		return self.TypeChoices(self.type)
106
107
	@type_enum.setter
108
	def type_enum(self, p_type):
109
		"""
110
		:type p_type: Verification.TypeChoices
111
		"""
112
		self.type = p_type.value
113
114
115
class UserProfile(User):
116
	name = CharField(max_length=30, null=True, blank=True)
117
118
	surname = CharField(max_length=30, null=True, blank=True)
119
	# tho email max length is 254 characted mysql supports unique keys only 767 bytes long (utf8 4 bytes = 767/4 = 191)
120
	email = models.EmailField(null=True, unique=True, blank=True, max_length=190)
121
	city = CharField(max_length=50, null=True, blank=True)
122
123
	birthday = DateField(null=True, blank=True)
124
	contacts = CharField(max_length=100, null=True, blank=True)
125
	# fileField + <img instead of ImageField (removes preview link)
126
	photo = FileField(upload_to=get_random_path, null=True, blank=True)
127
	suggestions = BooleanField(null=False, default=True)
128
	embedded_youtube = BooleanField(null=False, default=True)
129
	highlight_code = BooleanField(null=False, default=False)
130
	logs = BooleanField(null=False, default=JS_CONSOLE_LOGS)
131
	theme = CharField(max_length=16, null=False, default='color-reg')
132
	online_change_sound = BooleanField(null=False, default=True)
133
	incoming_file_call_sound = BooleanField(null=False, default=True)
134
	message_sound = BooleanField(null=False, default=True)
135
136
	email_verification = models.ForeignKey(Verification, null=True)
137
138
	def save(self, *args, **kwargs):
139
		"""
140
		http://stackoverflow.com/questions/15422606/django-model-email-field-unique-if-not-null-blank
141
		"""
142
		if self.email is not None:
143
			self.email.lower().strip()  # Hopefully reduces junk to ""
144
			if self.email == "":
145
				self.email = None
146
		super(UserProfile, self).save(*args, **kwargs)
147
148
149
class Room(models.Model):
150
	name = CharField(max_length=16, null=True, blank=True)
151
	users = models.ManyToManyField(User, related_name='rooms', through='RoomUsers')
152
	disabled = BooleanField(default=False, null=False)
153
154
	@property
155
	def is_private(self):
156
		return self.name is None
157
158
	def __unicode__(self):
159
		return self.__str__()
160
161
	def __str__(self):
162
		return "{}/{}".format(self.id, self.name)
163
164
165
def get_milliseconds(dt=None):
166
	if dt is None:
167
		return int(time.time()*1000)
168
	if dt.time.timestamp:
169
		return int(dt.time.timestamp()*1000)
170
	else:
171
		return mktime(dt.time.timetuple()) * 1000 + int(dt.time.microsecond / 1000)
172
173
174
class Message(models.Model):
175
	"""
176
	Contains all public messages
177
	"""
178
	sender = models.ForeignKey(User, related_name='sender')
179
	room = models.ForeignKey(Room, null=True)
180
	# DateField.auto_now
181
	time = models.BigIntegerField(default=get_milliseconds)
182
	content = models.TextField(null=True, blank=True)
183
	# if symbol = null - no images refers this row
184
	# symbol is the same as "select max(symbol) from images where message_id = message.id
185
	# we store symbol in this table in case if user edits message
186
	# - images that refers same message always have unique symbols
187
	symbol = models.CharField(null=True, max_length=1, blank=True)
188
	deleted = BooleanField(default=False)
189
	giphy = URLField(null=True, blank=True)
190
191
	def __unicode__(self):
192
		return self.__str__()
193
194
	def __str__(self):
195
196
		if self.content is None:
197
			v = ''
198
		elif len(self.content) > 50:
199
			v = self.content[:50]
200
		else:
201
			v = self.content
202
		v = json.dumps(v)
203
		return "{}/{}".format(self.id, v)
204
205
206
class Image(models.Model):
207
	# character in Message.content that will be replaced with this image
208
	symbol = models.CharField(null=False, max_length=1)
209
	message = models.ForeignKey(Message, related_name='message', null=False)
210
	img = FileField(upload_to=get_random_path, null=True)
211
212
	class Meta:
213
		unique_together = ('symbol', 'message')
214
215
216
class RoomUsers(models.Model):
217
	room = models.ForeignKey(Room, null=False)
218
	user = models.ForeignKey(User, null=False)
219
	last_read_message = models.ForeignKey(Message, null=True)
220
	volume = models.IntegerField(default=2, null=False)
221
	notifications = BooleanField(null=False, default=True)
222
223
	class Meta:  # pylint: disable=C1001
224
		unique_together = ("user", "room")
225
		db_table = ''.join((User._meta.app_label, '_room_users'))
226
227
228
class SubscriptionMessages(models.Model):
229
	message = models.ForeignKey(Message, null=False)
230
	subscription = models.ForeignKey(Subscription, null=False)
231
	received = BooleanField(null=False, default=False)
232
233
	class Meta:  # pylint: disable=C1001
234
		unique_together = ("message", "subscription")
235
		db_table = ''.join((User._meta.app_label, '_subscription_message'))
236
237
238
class Issue(models.Model):
239
	content = models.TextField(null=False)  # unique = true, but mysql doesnt allow unique fields for unspecified size
240
241
	def __str__(self):
242
		return self.content
243
244
245
class IssueDetails(models.Model):
246
	sender = models.ForeignKey(User, null=False)
247
	browser = models.CharField(null=False, max_length=32, blank=True)
248
	time = models.DateField(default=datetime.datetime.now, blank=True)
249
	issue = models.ForeignKey(Issue, related_name='issue')
250
	log = models.TextField(null=True, blank=True)
251
252
	class Meta:  # pylint: disable=C1001
253
		db_table = ''.join((User._meta.app_label, '_issue_detail'))
254
255
256
class IpAddress(models.Model):
257
	ip = models.CharField(null=False, max_length=32, unique=True)
258
	isp = models.CharField(null=True, max_length=32, blank=True)
259
	country_code = models.CharField(null=True, max_length=16, blank=True)
260
	country = models.CharField(null=True, max_length=32, blank=True)
261
	region = models.CharField(null=True, max_length=32, blank=True)
262
	city = models.CharField(null=True, max_length=32, blank=True)
263
264
	def __str__(self):
265
		return self.ip
266
267
	@property
268
	def info(self):
269
		if self.country is not None:
270
			return "{} {} ({})".format(self.country, self.city, self.isp)
271
		else:
272
			return ""
273
274
275
	class Meta:  # pylint: disable=C1001
276
		db_table = ''.join((User._meta.app_label, '_ip_address'))
277
278
279
class UserJoinedInfo(models.Model):
280
	ip = models.ForeignKey(IpAddress, null=True)
281
	user = models.ForeignKey(User, null=True)
282
	time = models.DateField(default=datetime.datetime.now)
283
284
	class Meta:  # pylint: disable=C1001
285
		db_table = ''.join((User._meta.app_label, '_user_joined_info'))
286
		unique_together = ("user", "ip")
287