Completed
Push — master ( af202d...0efa0e )
by Andrew
20s
created

SubscriptionMessages   A

Size/Duplication

Total Lines 8
Duplicated Lines 0 %

Importance

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