diff --git a/archilance/settings/base.py b/archilance/settings/base.py index 0aed8fc..74a36c2 100644 --- a/archilance/settings/base.py +++ b/archilance/settings/base.py @@ -31,6 +31,7 @@ DJANGO_APPS = [ THIRD_PARTY_APPS = [ 'django_extensions', + 'social.apps.django_app.default', 'mptt', 'registration', 'rest_framework', @@ -117,11 +118,67 @@ AUTH_PASSWORD_VALIDATORS = [ {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'}, ] + AUTHENTICATION_BACKENDS = ( + 'social.backends.facebook.FacebookOAuth2', + 'social.backends.google.GoogleOAuth2', + 'social.backends.twitter.TwitterOAuth', + 'social.backends.vk.VKOAuth2', + 'social.backends.odnoklassniki.OdnoklassnikiOAuth2', 'django.contrib.auth.backends.ModelBackend', - # 'guardian.backends.ObjectPermissionBackend', ) +# SOCIAL_AUTH_FACEBOOK_KEY = '222531191461451' +# SOCIAL_AUTH_FACEBOOK_SECRET = '95e88f7ef396c5b803375f8476cf2ba4' + +SOCIAL_AUTH_FACEBOOK_KEY = '1030546170341186' +SOCIAL_AUTH_FACEBOOK_SECRET = '1b22e95040b209c5d2f2d7f69462bf95' + +SOCIAL_AUTH_FACEBOOK_SCOPE = ['email'] +SOCIAL_AUTH_FACEBOOK_PROFILE_EXTRA_PARAMS = { + 'fields': 'id,email', +} + +SOCIAL_AUTH_ODNOKLASSNIKI_OAUTH2_KEY = '1247035904' +SOCIAL_AUTH_ODNOKLASSNIKI_OAUTH2_SECRET = '9AD83DB399405EEFAE7641BD' +SOCIAL_AUTH_ODNOKLASSNIKI_OAUTH2_PUBLIC_NAME = 'CBADEFFLEBABABABA' + +SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = '499898042244-bt7v18v4f46k8qg98n1ne8u2hjtmj0cn.apps.googleusercontent.com' +SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = 's69NCyhSlwY0OuGGT8_dFI7E' + +SOCIAL_AUTH_TWITTER_KEY = 'YAe05K4IYYxHhA6J1mTOdDBjq' +SOCIAL_AUTH_TWITTER_SECRET = 'iRuYqRRaoGkCD4ip74NICb8FeZMxvM6MZ8HLMbm1jX99o7pcaL' + +SOCIAL_AUTH_VK_OAUTH2_KEY = '5469025' +SOCIAL_AUTH_VK_OAUTH2_SECRET = '3Wild7HqYq6YFiLz9i7l' + +SOCIAL_AUTH_VK_OAUTH2_SCOPE = [ + 'notify', + 'friends', + 'email', +] + + +SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/' +SOCIAL_AUTH_NEW_USER_REDIRECT_URL = '/' +SOCIAL_AUTH_NEW_ASSOCIATION_REDIRECT_URL = '/' + +SOCIAL_AUTH_PIPELINE = ( + 'social.pipeline.social_auth.social_details', + 'social.pipeline.social_auth.social_uid', + 'social.pipeline.social_auth.auth_allowed', + 'social.pipeline.social_auth.social_user', + 'social.pipeline.user.get_username', + 'users.pipeline.add_email_for_user', + 'users.pipeline.test_contractor', + 'social.pipeline.mail.mail_validation', + 'social.pipeline.user.create_user', + 'social.pipeline.social_auth.associate_user', + 'social.pipeline.social_auth.load_extra_data', + 'social.pipeline.user.user_details', +) + +FIELDS_STORED_IN_SESSION = ['user_type'] # Internationalization # https://docs.djangoproject.com/en/1.9/topics/i18n/ @@ -155,6 +212,7 @@ ACCOUNT_ACTIVATION_DAYS = 7 REGISTRATION_AUTO_LOGIN = True LOGIN_REDIRECT_URL = '/projects/' + if DEBUG: EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend' diff --git a/archilance/urls.py b/archilance/urls.py index 1b11ed0..a3f1c9e 100644 --- a/archilance/urls.py +++ b/archilance/urls.py @@ -9,12 +9,14 @@ from .views import HomeTemplateView, TestChatTemplateView urlpatterns = [ url(r'^$', HomeTemplateView.as_view()), + url('', include('social.apps.django_app.urls', namespace='social')), url(r'^chattest$', TestChatTemplateView.as_view()), url(r'^work_sell/', include('work_sell.urls')), url(r'^test/$', TemplateView.as_view(template_name='test.html'), name='test'), url(r'^projects/', include('projects.urls')), url(r'^chat/', include('chat.urls')), url(r'^specializations/', include('specializations.urls')), + url(r'^users/', include('registration.backends.default.urls')), url(r'^users/', include('users.urls')), url(r'^admin/', admin.site.urls), diff --git a/projects/templates/project_list.html b/projects/templates/project_list.html index a41a3cb..eaa26d0 100644 --- a/projects/templates/project_list.html +++ b/projects/templates/project_list.html @@ -12,33 +12,26 @@
-
Тип работ:
Специализации:
+
-
-
- -
-
- -
-
- -
-
- -
-
+
+
+ +
+
+ +
+
+ +
+
+ +
+ +
@@ -67,30 +60,28 @@
-
Тип работ:
-
Специализации:
-
+
Классификация здания
+
Вид строительства
+
Местоположение
diff --git a/requirements/base.txt b/requirements/base.txt index 9a56303..24b834c 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -1,8 +1,10 @@ Django==1.9.6 Momoko==2.2.3 Pillow==3.2.0 +PyJWT==1.4.0 Werkzeug==0.11.10 backports-abc==0.4 +defusedxml==0.4.1 django-appconf==1.0.2 django-compressor==2.0 django-debug-toolbar==1.4 @@ -17,12 +19,16 @@ djangorestframework==3.3.3 djangorestframework-filters==0.8.0 fake-factory==0.5.7 jsonschema==2.5.1 +oauthlib==1.1.2 psycopg2==2.6.1 pydash==3.4.3 python-dateutil==2.5.3 +python-social-auth==0.2.19 +python3-openid==3.0.10 rcssmin==1.0.6 redis==2.10.5 requests==2.10.0 +requests-oauthlib==0.6.1 rjsmin==1.0.12 six==1.10.0 sorl-thumbnail==12.3 @@ -30,3 +36,4 @@ sqlparse==0.1.19 tornado==4.3 + diff --git a/templates/registration/login.html b/templates/registration/login.html index 88aeb7b..b4d02ba 100644 --- a/templates/registration/login.html +++ b/templates/registration/login.html @@ -5,6 +5,7 @@

Вход на сайт

+ {{ form.errors }}
{% csrf_token %}
diff --git a/templates/registration/registration_form.html b/templates/registration/registration_form.html index e23d5c0..b9ccc5f 100644 --- a/templates/registration/registration_form.html +++ b/templates/registration/registration_form.html @@ -1,5 +1,6 @@ {% extends 'partials/base.html' %} {% block content %} + {% include 'partials/header.html' %}

Регистрация

@@ -14,6 +15,9 @@ {% endif %}
+ +
+
@@ -26,6 +30,43 @@
+
+
+
+ +
+ + fb + +
+ +
+ + tw + +
+ +
+ + gplus + +
+ +
+ + vk + +
+ +
+ + yt + +
+ +
+
+
diff --git a/users/admin.py b/users/admin.py index 227bdbd..4e404c4 100644 --- a/users/admin.py +++ b/users/admin.py @@ -5,7 +5,7 @@ from .models import User, Team, ContractorFinancialInfo class UserAdmin(admin.ModelAdmin): readonly_fields = ('pk',) - list_display = ('email', 'get_groups', 'cro', 'is_active',) + list_display = ('username', 'email', 'get_groups', 'cro', 'is_active',) def get_groups(self, obj): return ', '.join(g.name for g in obj.groups.all()) diff --git a/users/migrations/0019_auto_20160708_1653.py b/users/migrations/0019_auto_20160708_1653.py new file mode 100644 index 0000000..49c289e --- /dev/null +++ b/users/migrations/0019_auto_20160708_1653.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.6 on 2016-07-08 13:53 +from __future__ import unicode_literals + +import datetime +from django.db import migrations, models +import django.utils.timezone +from django.utils.timezone import utc + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0018_auto_20160630_1846'), + ] + + operations = [ + # migrations.RemoveField( + # model_name='user', + # name='nickname', + # ), + # migrations.AddField( + # model_name='user', + # name='data_joined', + # field=models.DateTimeField(default=django.utils.timezone.now), + # ), + # migrations.AddField( + # model_name='user', + # name='username', + # field=models.CharField(default=datetime.datetime(2016, 7, 8, 13, 53, 51, 625003, tzinfo=utc), max_length=50, unique=True), + # preserve_default=False, + # ), + migrations.AlterField( + model_name='user', + name='date_of_birth', + field=models.DateTimeField(blank=True, null=True), + ), + ] diff --git a/users/models.py b/users/models.py index 48560b4..62b9833 100644 --- a/users/models.py +++ b/users/models.py @@ -8,17 +8,19 @@ from specializations.models import Specialization class UserManager(BaseUserManager): - def create_user(self, email, password=None): + def create_user(self, username, email, password=None, **kwargs): + # import code; code.interact(local=dict(globals(), **locals())) if not email: raise ValueError('Users must have an email address') - user = self.model(email=UserManager.normalize_email(email),) + user = self.model(username=username, + email=UserManager.normalize_email(email),) user.set_password(password) user.save(using=self._db) return user - def create_superuser(self, email, password): - user = self.create_user(email, password) + def create_superuser(self, username, password): + user = self.create_user(username, "admin@exampletest.com", password) user.is_superuser = True user.save(using=self._db) return user @@ -81,13 +83,14 @@ class User(AbstractBaseUser, PermissionsMixin): ('busy', 'Занят'), ) - nickname = models.CharField(max_length=50, blank=True,null=True) + username = models.CharField(max_length=50, unique=True) first_name = models.CharField(max_length=255, blank=True) last_name = models.CharField(max_length=255, blank=True) patronym = models.CharField(max_length=255, blank=True) email = models.EmailField(max_length=255, unique=True, db_index=True) is_active = models.BooleanField(default=True) created = models.DateTimeField(default=timezone.now) + data_joined = models.DateTimeField(default=timezone.now) last_time_visit = models.DateTimeField(default=timezone.now) contractor_specializations = TreeManyToManyField(Specialization, related_name='contractors', blank=True) contractor_status = models.CharField(default='free', max_length=20, choices=STATUSES) @@ -97,7 +100,7 @@ class User(AbstractBaseUser, PermissionsMixin): gender = models.CharField(max_length=30, choices=GENDERS, blank=True) cro = models.BooleanField(default=False) website = models.CharField(max_length=255, blank=True) - date_of_birth = models.DateTimeField() + date_of_birth = models.DateTimeField(null=True,blank=True) avatar = models.ImageField(upload_to='users/avatars/', blank=True) phone = models.CharField(max_length=30, blank=True, null=True) @@ -121,7 +124,7 @@ class User(AbstractBaseUser, PermissionsMixin): def get_profile_image(self): return self.avatar - USERNAME_FIELD = 'email' + USERNAME_FIELD = 'username' REQUIRED_FIELDS = [] objects = UserManager() contractor_objects = ContractorUserManager() diff --git a/users/pipeline.py b/users/pipeline.py new file mode 100644 index 0000000..b751fc3 --- /dev/null +++ b/users/pipeline.py @@ -0,0 +1,27 @@ +from django.shortcuts import redirect, render_to_response + +from social.pipeline.partial import partial + +@partial +def test_contractor(backend, details, response, is_new=False, *args, **kwargs): + import code; code.interact(local=dict(globals(), **locals())) + + +@partial +def add_email_for_user(backend, details, response, is_new=False, *args, **kwargs): + data = backend.strategy.request_data() + if details.get('contractor') is None: + return render_to_response('add_email_form.html') + else: + return {'contractor': details.get('contractor')} + +@partial +def require_email(strategy, details, user=None, is_new=False, *args, **kwargs): + if kwargs.get('ajax') or user and user.email: + return + elif is_new and not details.get('email'): + email = strategy.request_data().get('email') + if email: + details['email'] = email + else: + return redirect('require_email') diff --git a/users/templates/add_email_form.html b/users/templates/add_email_form.html new file mode 100644 index 0000000..c279603 --- /dev/null +++ b/users/templates/add_email_form.html @@ -0,0 +1,5 @@ +

Введите свой email

+ + + + diff --git a/users/templates/portfolio_create_form.html b/users/templates/portfolio_create_form.html index fc9ba9c..7c0a056 100644 --- a/users/templates/portfolio_create_form.html +++ b/users/templates/portfolio_create_form.html @@ -40,10 +40,10 @@

Бюджет{{ portfolio_form.budget.errors.as_text }}

-
+
-
+
{{ portfolio_form.currency}}
@@ -52,10 +52,10 @@

Срок выполнения{{ portfolio_form.budget.errors.as_text }}

-
+
-
+
{{ portfolio_form.term_type }}
@@ -73,7 +73,7 @@
- +
diff --git a/work_sell/templates/upload.html b/work_sell/templates/upload.html new file mode 100644 index 0000000..2ffa6c3 --- /dev/null +++ b/work_sell/templates/upload.html @@ -0,0 +1,6 @@ +{% extends 'partials/base.html' %} + +{% block content %} +

Upload Files

+ +{% endblock %} diff --git a/work_sell/urls.py b/work_sell/urls.py index c755e47..384e97f 100644 --- a/work_sell/urls.py +++ b/work_sell/urls.py @@ -6,6 +6,7 @@ from .views import ( WorkSellCreateView, WorkSellUpdateView, WorkSellDeleteView, + UploadView, work_sell_create, ) @@ -14,6 +15,7 @@ app_name = 'work_sell' urlpatterns = [ urls.url(r'^$', WorkSellsView.as_view(), name='list'), urls.url(r'^create/$', WorkSellCreateView.as_view(), name='create'), + urls.url(r'^upload/$', UploadView.as_view(), name='upload'), urls.url(r'^(?P\d+)/edit/$',WorkSellUpdateView.as_view(), name='edit'), urls.url(r'^(?P\d+)/delete/$',WorkSellDeleteView.as_view(), name='delete'), urls.url(r'^test/$', work_sell_create, name='test'), diff --git a/work_sell/views.py b/work_sell/views.py index 7909a52..53be4a5 100644 --- a/work_sell/views.py +++ b/work_sell/views.py @@ -2,7 +2,8 @@ import json from django.shortcuts import render from django.core.urlresolvers import reverse from django.http import JsonResponse, HttpResponse -from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView, TemplateView +from django.views.generic import ListView, DetailView, CreateView, View,\ + UpdateView, DeleteView, TemplateView from projects.models import BuildingClassfication, ConstructionType from .models import WorkSell @@ -75,6 +76,13 @@ class WorkSellDeleteView(DeleteView): return reverse('work_sell:list') + +class UploadView(View): + template_name = 'upload.html' + + def get(self, request, *args, **kwargs): + return render(request,self.template_name) + class JSONResponseMixin(object): def render_to_json_response(self, context, **response_kwargs): return JsonResponse(