Completed
Push — master ( 4881fb...bd9c82 )
by Andrew
33s
created

dummy_worker()   A

Complexity

Conditions 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
1
# -*- encoding: utf-8 -*-
2
import datetime
3
import json
4
5
from django.conf import settings
6
from django.contrib.auth import authenticate
7
from django.contrib.auth import login as djangologin
8
from django.contrib.auth import logout as djangologout
9
10
try:
11
	from django.template.context_processors import csrf
12
except ImportError:
13
	from django.core.context_processors import csrf
14
from django.core.exceptions import ObjectDoesNotExist, ValidationError
15
from django.db import transaction
16
from django.db.models import Count, Q
17
from django.http import Http404
18
from django.utils.timezone import utc
19
from django.http import HttpResponse
20
from django.http import HttpResponseRedirect
21
from django.shortcuts import render_to_response
22
from django.template import RequestContext
23
from django.views.decorators.http import require_http_methods
24
from django.views.generic import View
25
from chat import utils
26
from chat.decorators import login_required_no_redirect
27
from chat.forms import UserProfileForm, UserProfileReadOnlyForm
28
from chat.models import Issue, IssueDetails, IpAddress, UserProfile, Verification
29
from chat.settings import VALIDATION_IS_OK, DATE_INPUT_FORMATS_JS, logging
30
from chat.utils import hide_fields, check_user, check_password, check_email, extract_photo, send_sign_up_email, \
31
	create_user_model, check_captcha, send_reset_password_email
32
33
logger = logging.getLogger(__name__)
34
RECAPTCHA_SITE_KEY = getattr(settings, "RECAPTCHA_SITE_KEY", None)
35
RECAPTHCA_SITE_URL = getattr(settings, "RECAPTHCA_SITE_URL", None)
36
GOOGLE_OAUTH_2_CLIENT_ID = getattr(settings, "GOOGLE_OAUTH_2_CLIENT_ID", None)
37
GOOGLE_OAUTH_2_JS_URL = getattr(settings, "GOOGLE_OAUTH_2_JS_URL", None)
38
FACEBOOK_APP_ID = getattr(settings, "FACEBOOK_APP_ID", None)
39
FACEBOOK_JS_URL = getattr(settings, "FACEBOOK_JS_URL", None)
40
41
# TODO doesn't work
42
def handler404(request):
43
	return HttpResponse("Page not found", content_type='text/plain')
44
45
46
@require_http_methods(['POST'])
47
def validate_email(request):
48
	"""
49
	POST only, validates email during registration
50
	"""
51
	email = request.POST.get('email')
52
	try:
53
		utils.check_email(email)
54
		response = VALIDATION_IS_OK
55
	except ValidationError as e:
56
		response = e.message
57
	return HttpResponse(response, content_type='text/plain')
58
59
60
@require_http_methods('POST')
61
def validate_user(request):
62
	"""
63
	Validates user during registration
64
	"""
65
	try:
66
		username = request.POST.get('username')
67
		utils.check_user(username)
68
		# hardcoded ok check in register.js
69
		message = VALIDATION_IS_OK
70
	except ValidationError as e:
71
		message = e.message
72
	return HttpResponse(message, content_type='text/plain')
73
74
75
@require_http_methods('GET')
76
@login_required_no_redirect(False)
77
def home(request):
78
	"""
79
	Login or logout navbar is creates by means of create_nav_page
80
	@return:  the x intercept of the line M{y=m*x+b}.
81
	"""
82
	context = csrf(request)
83
	up = UserProfile.objects.defer('suggestions', 'notifications', 'cache_messages').get(id=request.user.id)
84
	context['suggestions'] = up.suggestions
85
	context['notifications'] = up.notifications
86
	context['cache_messages'] = up.cache_messages
87
	return render_to_response('chat.html', context, context_instance=RequestContext(request))
88
89
90
@login_required_no_redirect(True)
91
def logout(request):
92
	"""
93
	POST. Logs out into system.
94
	"""
95
	djangologout(request)
96
	return HttpResponseRedirect('/')
97
98
99
@login_required_no_redirect(True)
100
def dummy_worker(request):
101
	"""
102
	POST. Logs out into system.
103
	"""
104
	return HttpResponse("var a = 3;", content_type='application/x-javascript')
105
106
107
@require_http_methods(['POST'])
108
def auth(request):
109
	"""
110
	Logs in into system.
111
	"""
112
	username = request.POST.get('username')
113
	password = request.POST.get('password')
114
	user = authenticate(username=username, password=password)
115
	if user is not None:
116
		djangologin(request, user)
117
		message = VALIDATION_IS_OK
118
	else:
119
		message = 'Login or password is wrong'
120
	logger.debug('Auth request %s ; Response: %s', hide_fields(request.POST, ('password',)), message)
121
	return HttpResponse(message, content_type='text/plain')
122
123
124
def send_restore_password(request):
125
	"""
126
	Sends email verification code
127
	"""
128
	logger.debug('Recover password request %s', request)
129
	try:
130
		username_or_password = request.POST.get('username_or_password')
131
		check_captcha(request)
132
		user_profile = UserProfile.objects.get(Q(username=username_or_password) | Q(email=username_or_password))
133
		if not user_profile.email:
134
			raise ValidationError("You didn't specify email address for this user")
135
		verification = Verification(type_enum=Verification.TypeChoices.password, user_id=user_profile.id)
136
		verification.save()
137
		send_reset_password_email(request, user_profile, verification)
138
		message = VALIDATION_IS_OK
139
		logger.debug('Verification email has been send for token %s to user %s(id=%d)',
140
				verification.token, user_profile.username, user_profile.id)
141
	except UserProfile.DoesNotExist:
142
		message = "User with this email or username doesn't exist"
143
		logger.debug("Skipping password recovery request for nonexisting user")
144
	except (UserProfile.DoesNotExist, ValidationError) as e:
145
		logger.debug('Not sending verification email because %s', e)
146
		message = 'Unfortunately we were not able to send you restore password email because {}'.format(e)
147
	return HttpResponse(message, content_type='text/plain')
148
149
150
def get_html_restore_pass():
151
	""""""
152
153
class RestorePassword(View):
154
155
	def get_user_by_code(self, token):
156
		"""
157
		:param token: token code to verify
158
		:type token: str
159
		:raises ValidationError: if token is not usable
160
		:return: UserProfile, Verification: if token is usable
161
		"""
162
		try:
163
			v = Verification.objects.get(token=token)
164
			if v.type_enum != Verification.TypeChoices.password:
165
				raise ValidationError("it's not for this operation ")
166
			if v.verified:
167
				raise ValidationError("it's already used")
168
			# TODO move to sql query or leave here?
169
			if v.time < datetime.datetime.utcnow().replace(tzinfo=utc) - datetime.timedelta(days=1):
170
				raise ValidationError("it's expired")
171
			return UserProfile.objects.get(id=v.user_id), v
172
		except Verification.DoesNotExist:
173
			raise ValidationError('Unknown verification token')
174
175
	@transaction.atomic
176
	def post(self, request):
177
		"""
178
		Sends email verification token
179
		"""
180
		token = request.POST.get('token', False)
181
		try:
182
			logger.debug('Proceed Recover password with token %s', token)
183
			user, verification = self.get_user_by_code(token)
184
			password = request.POST.get('password')
185
			check_password(password)
186
			user.set_password(password)
187
			user.save(update_fields=('password',))
188
			verification.verified = True
189
			verification.save(update_fields=('verified',))
190
			logger.info('Password has been change for token %s user %s(id=%d)', token, user.username, user.id)
191
			response = VALIDATION_IS_OK
192
		except ValidationError as e:
193
			logger.debug('Rejecting verification token %s because %s', token, e)
194
			response = "".join(("You can't reset password with this token because ", str(e)))
195
		return HttpResponse(response, content_type='text/plain')
196
197
	def get(self, request):
198
		token = request.GET.get('token', False)
199
		logger.debug('Rendering restore password page with token  %s', token)
200
		try:
201
			user = self.get_user_by_code(token)[0]
202
			response = {
203
				'message': VALIDATION_IS_OK,
204
				'restore_user': user.username,
205
				'token': token
206
			}
207
		except ValidationError as e:
208
			logger.debug('Rejecting verification token %s because %s', token, e)
209
			response = {'message': "Unable to confirm email with token {} because {}".format(token, e)}
210
		return render_to_response('reset_password.html', response, context_instance=RequestContext(request))
211
212
213
@require_http_methods('GET')
214
def confirm_email(request):
215
	"""
216
	Accept the verification token sent to email
217
	"""
218
	token = request.GET.get('token', False)
219
	logger.debug('Processing email confirm with token  %s', token)
220
	try:
221
		try:
222
			v = Verification.objects.get(token=token)
223
		except Verification.DoesNotExist:
224
			raise ValidationError('Unknown verification token')
225
		if v.type_enum != Verification.TypeChoices.register:
226
			raise ValidationError('This is not confirm email token')
227
		if v.verified:
228
			raise ValidationError('This verification token already accepted')
229
		user = UserProfile.objects.get(id=v.user_id)
230
		if user.email_verification_id != v.id:
231
			raise ValidationError('Verification token expired because you generated another one')
232
		v.verified = True
233
		v.save(update_fields=['verified'])
234
		message = VALIDATION_IS_OK
235
		logger.info('Email verification token %s has been accepted for user %s(id=%d)', token, user.username, user.id)
236
	except Exception as e:
237
		logger.debug('Rejecting verification token %s because %s', token, e)
238
		message = ("Unable to confirm email with token {} because {}".format(token, e))
239
	response = {'message': message}
240
	return render_to_response('confirm_mail.html', response, context_instance=RequestContext(request))
241
242
243
@require_http_methods('GET')
244
def show_profile(request, profile_id):
245
	try:
246
		user_profile = UserProfile.objects.get(pk=profile_id)
247
		form = UserProfileReadOnlyForm(instance=user_profile)
248
		form.username = user_profile.username
249
		return render_to_response(
250
			'show_profile.html',
251
			{'form': form},
252
			context_instance=RequestContext(request)
253
		)
254
	except ObjectDoesNotExist:
255
		raise Http404
256
257
258
@require_http_methods('GET')
259
def statistics(request):
260
	pie_data = IpAddress.objects.values('country').filter(country__isnull=False).annotate(count=Count("country"))
261
	return HttpResponse(json.dumps(list(pie_data)), content_type='application/json')
262
263
264
@login_required_no_redirect()
265
@transaction.atomic
266
def report_issue(request):
267
	logger.info('Saving issue: %s', hide_fields(request.POST, ('log',), huge=True))
268
	issue = Issue.objects.get_or_create(content=request.POST['issue'])[0]
269
	issue_details = IssueDetails(
270
		sender_id=request.user.id,
271
		browser=request.POST.get('browser'),
272
		issue=issue,
273
		log=request.POST.get('log')
274
	)
275
	issue_details.save()
276
	return HttpResponse(VALIDATION_IS_OK, content_type='text/plain')
277
278
279
class ProfileView(View):
280
281
	@login_required_no_redirect()
282
	def get(self, request):
283
		user_profile = UserProfile.objects.get(pk=request.user.id)
284
		form = UserProfileForm(instance=user_profile)
285
		c = csrf(request)
286
		c['form'] = form
287
		c['date_format'] = DATE_INPUT_FORMATS_JS
288
		return render_to_response('change_profile.html', c, context_instance=RequestContext(request))
289
290
	@login_required_no_redirect()
291
	def post(self, request):
292
		logger.info('Saving profile: %s', hide_fields(request.POST, ("base64_image", ), huge=True))
293
		user_profile = UserProfile.objects.get(pk=request.user.id)
294
		image_base64 = request.POST.get('base64_image')
295
296
		if image_base64 is not None:
297
			image = extract_photo(image_base64)
298
			request.FILES['photo'] = image
299
300
		form = UserProfileForm(request.POST, request.FILES, instance=user_profile)
301
		if form.is_valid():
302
			profile = form.save()
303
			response = profile. photo.url if 'photo' in  request.FILES else VALIDATION_IS_OK
304
		else:
305
			response = form.errors
306
		return HttpResponse(response, content_type='text/plain')
307
308
309
class RegisterView(View):
310
311
	def get(self, request):
312
		logger.debug(
313
			'Rendering register page with captcha site key %s and oauth key %s',
314
			RECAPTCHA_SITE_KEY, GOOGLE_OAUTH_2_CLIENT_ID
315
		)
316
		c = csrf(request)
317
		c['captcha_key'] = RECAPTCHA_SITE_KEY
318
		c['captcha_url'] = RECAPTHCA_SITE_URL
319
		c['oauth_url'] = GOOGLE_OAUTH_2_JS_URL
320
		c['oauth_token'] = GOOGLE_OAUTH_2_CLIENT_ID
321
		c['fb_app_id'] = FACEBOOK_APP_ID
322
		c['fb_js_url'] = FACEBOOK_JS_URL
323
		return render_to_response("register.html", c, context_instance=RequestContext(request))
324
325
	@transaction.atomic
326
	def post(self, request):
327
		try:
328
			rp = request.POST
329
			logger.info('Got register request %s', hide_fields(rp, ('password', 'repeatpassword')))
330
			(username, password, email) = (rp.get('username'), rp.get('password'), rp.get('email'))
331
			check_user(username)
332
			check_password(password)
333
			check_email(email)
334
			user_profile = UserProfile(username=username, email=email, sex_str=rp.get('sex'))
335
			user_profile.set_password(password)
336
			create_user_model(user_profile)
337
			# You must call authenticate before you can call login
338
			auth_user = authenticate(username=username, password=password)
339
			message = VALIDATION_IS_OK  # redirect
340
			if email:
341
				send_sign_up_email(user_profile, request.get_host(), request)
342
			djangologin(request, auth_user)
343
		except ValidationError as e:
344
			message = e.message
345
			logger.debug('Rejecting request because "%s"', message)
346
		return HttpResponse(message, content_type='text/plain')
347