diff options
| author | Andrew <saintruler@gmail.com> | 2019-03-11 21:00:02 +0400 |
|---|---|---|
| committer | Andrew <saintruler@gmail.com> | 2019-03-11 21:00:02 +0400 |
| commit | 7e7dd5244e8d26485ad7950a89c04c98c4fef83f (patch) | |
| tree | 810730c4650392080fb87a78d3b527201e89fe4b /backend | |
Initial commit/
Diffstat (limited to 'backend')
29 files changed, 498 insertions, 0 deletions
diff --git a/backend/EcoAlert/__init__.py b/backend/EcoAlert/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/backend/EcoAlert/__init__.py diff --git a/backend/EcoAlert/settings.py b/backend/EcoAlert/settings.py new file mode 100644 index 0000000..810aa9a --- /dev/null +++ b/backend/EcoAlert/settings.py @@ -0,0 +1,148 @@ +""" +Django settings for EcoAlert project. + +Generated by 'django-admin startproject' using Django 2.1.5. + +For more information on this file, see +https://docs.djangoproject.com/en/2.1/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/2.1/ref/settings/ +""" + +import os + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = '-vihnj-@%qsmy6py(%$(d0kk*k@c)$2dm-7v_3+3owgm#5oe#1' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = ['*'] + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + + 'django.contrib.sites', + + 'corsheaders', + 'allauth', + 'allauth.account', + + 'rest_framework', + 'rest_framework.authtoken', + 'rest_auth', + 'rest_auth.registration', + 'articles' +] + +MIDDLEWARE = [ + 'corsheaders.middleware.CorsMiddleware', + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'EcoAlert.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(BASE_DIR, 'templates')] + , + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'EcoAlert.wsgi.application' + +# Database +# https://docs.djangoproject.com/en/2.1/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + } +} + +# Password validation +# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + +# Internationalization +# https://docs.djangoproject.com/en/2.1/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/2.1/howto/static-files/ + +STATIC_URL = '/static/' + +MEDIA_ROOT = os.path.join(BASE_DIR, 'media') +MEDIA_URL = '/media/' + +AUTH_USER_MODEL = 'articles.User' +CORS_ORIGIN_ALLOW_ALL = True + +REST_AUTH_SERIALIZERS = { + 'USER_DETAILS_SERIALIZER': 'articles.api.serializers.UserSerializer', + 'TOKEN_SERIALIZER': 'articles.api.serializers.TokenSerializer' + +} +REST_AUTH_REGISTER_SERIALIZERS = { + 'REGISTER_SERIALIZER': 'articles.api.serializers.CustomRegisterSerializer', +} + +SITE_ID = 1 +ACCOUNT_EMAIL_VERIFICATION = 'none' +ACCOUNT_AUTHENTICATION_METHOD = 'username' +ACCOUNT_EMAIL_REQUIRED = False diff --git a/backend/EcoAlert/urls.py b/backend/EcoAlert/urls.py new file mode 100644 index 0000000..ba866a8 --- /dev/null +++ b/backend/EcoAlert/urls.py @@ -0,0 +1,27 @@ +"""EcoAlert URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/2.1/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.conf.urls.static import static +from django.contrib import admin +from django.urls import path, include + +from EcoAlert import settings + +urlpatterns = [ + path('rest-auth/', include('rest_auth.urls')), + path('rest-auth/registration/', include('rest_auth.registration.urls')), + path('admin/', admin.site.urls), + path('api/', include('articles.api.urls')) + ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/backend/EcoAlert/wsgi.py b/backend/EcoAlert/wsgi.py new file mode 100644 index 0000000..d31e423 --- /dev/null +++ b/backend/EcoAlert/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for EcoAlert project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'EcoAlert.settings') + +application = get_wsgi_application() diff --git a/backend/LICENSE b/backend/LICENSE new file mode 100644 index 0000000..57f44b2 --- /dev/null +++ b/backend/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Leonid + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/backend/articles/__init__.py b/backend/articles/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/backend/articles/__init__.py diff --git a/backend/articles/admin.py b/backend/articles/admin.py new file mode 100644 index 0000000..ee1a3ff --- /dev/null +++ b/backend/articles/admin.py @@ -0,0 +1,39 @@ +from django.contrib import admin + +# Register your models here. +from django.contrib.auth.admin import UserAdmin as BaseUserAdmin +from articles.models import Article, User +from django.contrib.auth.models import Group + + +class UserAdmin(BaseUserAdmin): + add_fieldsets = ( + (None, { + 'fields': ( + 'username', 'email', 'bio', 'avatar', 'password1', + 'password2') + }), + ('Permissions', { + 'fields': ('is_superuser', 'is_staff') + }) + ) + + fieldsets = ( + (None, { + 'fields': ( + 'username', 'email', 'bio', 'avatar', 'password') + }), + ('Permissions', { + 'fields': ('is_superuser', 'is_staff') + }) + ) + + list_display = ['username', 'email'] + search_fields = ('email', 'username') + ordering = ('email',) + + +admin.site.register(User, UserAdmin) +admin.site.register(Article) + +admin.site.unregister(Group) diff --git a/backend/articles/api/serializers.py b/backend/articles/api/serializers.py new file mode 100644 index 0000000..f8629e8 --- /dev/null +++ b/backend/articles/api/serializers.py @@ -0,0 +1,59 @@ +from rest_framework import serializers +from rest_auth.registration.serializers import RegisterSerializer +from articles.models import Article, User +from allauth.account.adapter import get_adapter +from rest_framework.authtoken.models import Token + + +class ArticleSerializer(serializers.ModelSerializer): + class Meta: + model = Article + fields = ( + 'id', 'title', 'image', 'text', 'rating', 'n_comments', 'author', 'is_solved', 'city', 'address', 'lat', 'lon') + + +class UserSerializer(serializers.ModelSerializer): + class Meta: + model = User + fields = ('username', 'email', 'bio', 'avatar', 'password', + ) + + +class CustomRegisterSerializer(RegisterSerializer): + + class Meta: + model = User + fields = ('username', 'email', 'password') + + def get_cleaned_data(self): + return { + 'username': self.validated_data.get('username', ''), + 'password1': self.validated_data.get('password1', ''), + 'password2': self.validated_data.get('password2', ''), + 'email': self.validated_data.get('email', ''), + + } + + def save(self, request): + adapter = get_adapter() + user = adapter.new_user(request) + + self.cleaned_data = self.get_cleaned_data() + + user.save() + adapter.save_user(request, user, self) + return user + + +class TokenSerializer(serializers.ModelSerializer): + user_info = serializers.SerializerMethodField() + + class Meta: + model = Token + fields = ('key', 'user', 'user_info') + + def get_user_info(self, obj): + serializer_data = UserSerializer(obj.user).data + del serializer_data['password'] + + return serializer_data diff --git a/backend/articles/api/urls.py b/backend/articles/api/urls.py new file mode 100644 index 0000000..f8bf0d5 --- /dev/null +++ b/backend/articles/api/urls.py @@ -0,0 +1,7 @@ +from rest_framework.routers import DefaultRouter +from .views import UserViewSet, ArticleViewSet + +router = DefaultRouter() +router.register(r'users', UserViewSet, base_name='users') +router.register(r'articles', ArticleViewSet, base_name='articles') +urlpatterns = router.urls diff --git a/backend/articles/api/views.py b/backend/articles/api/views.py new file mode 100644 index 0000000..209f71f --- /dev/null +++ b/backend/articles/api/views.py @@ -0,0 +1,16 @@ +from rest_framework.generics import ListAPIView, RetrieveAPIView +from ..models import User +from .serializers import UserSerializer +from articles.models import Article +from .serializers import ArticleSerializer +from rest_framework import viewsets + + +class UserViewSet(viewsets.ModelViewSet): + serializer_class = UserSerializer + queryset = User.objects.all() + + +class ArticleViewSet(viewsets.ModelViewSet): + serializer_class = ArticleSerializer + queryset = Article.objects.all() diff --git a/backend/articles/apps.py b/backend/articles/apps.py new file mode 100644 index 0000000..bc12dfb --- /dev/null +++ b/backend/articles/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class ArticlesConfig(AppConfig): + name = 'articles' diff --git a/backend/articles/forms.py b/backend/articles/forms.py new file mode 100644 index 0000000..63444a1 --- /dev/null +++ b/backend/articles/forms.py @@ -0,0 +1,15 @@ +from django import forms +from django.contrib.auth.forms import UserCreationForm, UserChangeForm +from .models import User + + +class CustomUserCreationForm(UserCreationForm): + class Meta(UserCreationForm): + model = User + fields = ('username', 'email') + + +class CustomUserChangeForm(UserChangeForm): + class Meta: + model = User + fields = ('username', 'email') diff --git a/backend/articles/migrations/0001_initial.py b/backend/articles/migrations/0001_initial.py new file mode 100644 index 0000000..79eb3ae --- /dev/null +++ b/backend/articles/migrations/0001_initial.py @@ -0,0 +1,61 @@ +# Generated by Django 2.1.5 on 2019-02-28 07:23 + +from django.conf import settings +import django.contrib.auth.models +import django.contrib.auth.validators +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0009_alter_user_last_name_max_length'), + ] + + operations = [ + migrations.CreateModel( + name='User', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), + ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), + ('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')), + ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), + ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), + ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), + ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), + ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), + ('bio', models.TextField(blank=True, max_length=500)), + ('avatar', models.ImageField(blank=True, upload_to='avatars/')), + ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), + ], + options={ + 'verbose_name': 'user', + 'verbose_name_plural': 'users', + 'abstract': False, + }, + managers=[ + ('objects', django.contrib.auth.models.UserManager()), + ], + ), + migrations.CreateModel( + name='Article', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=30)), + ('text', models.TextField()), + ('image', models.ImageField(upload_to='article_images/')), + ('rating', models.IntegerField(default=0)), + ('n_comments', models.IntegerField(default=0)), + ('is_solved', models.BooleanField(default=0)), + ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/backend/articles/migrations/0002_auto_20190228_0732.py b/backend/articles/migrations/0002_auto_20190228_0732.py new file mode 100644 index 0000000..74c816a --- /dev/null +++ b/backend/articles/migrations/0002_auto_20190228_0732.py @@ -0,0 +1,33 @@ +# Generated by Django 2.1.5 on 2019-02-28 07:32 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('articles', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='article', + name='address', + field=models.CharField(default='Не указано', max_length=100), + ), + migrations.AddField( + model_name='article', + name='city', + field=models.CharField(default='Не указано', max_length=30), + ), + migrations.AddField( + model_name='article', + name='lat', + field=models.FloatField(default=0.0), + ), + migrations.AddField( + model_name='article', + name='lon', + field=models.FloatField(default=0.0), + ), + ] diff --git a/backend/articles/migrations/__init__.py b/backend/articles/migrations/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/backend/articles/migrations/__init__.py diff --git a/backend/articles/models.py b/backend/articles/models.py new file mode 100644 index 0000000..fdde780 --- /dev/null +++ b/backend/articles/models.py @@ -0,0 +1,30 @@ +from django.contrib.auth.models import AbstractUser +from django.db import models +from django.utils.translation import gettext_lazy as _ + +from EcoAlert.settings import AUTH_USER_MODEL + + +class User(AbstractUser): + bio = models.TextField(max_length=500, blank=True) + avatar = models.ImageField(upload_to='avatars/', blank=True) + + def __str__(self): + return self.username + + +class Article(models.Model): + author = models.ForeignKey(AUTH_USER_MODEL, on_delete=models.CASCADE) + city = models.CharField(max_length=30, default='Не указано') + address = models.CharField(max_length=100, default='Не указано') + title = models.CharField(max_length=30) + text = models.TextField() + image = models.ImageField(upload_to='article_images/', default='../media/article_images/') + rating = models.IntegerField(default=0) + n_comments = models.IntegerField(default=0) + is_solved = models.BooleanField(default=0) + lat = models.FloatField(default=0.0) + lon = models.FloatField(default=0.0) + + def __str__(self): + return self.title diff --git a/backend/articles/tests.py b/backend/articles/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/backend/articles/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/backend/articles/views.py b/backend/articles/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/backend/articles/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/backend/db.sqlite3 b/backend/db.sqlite3 Binary files differnew file mode 100644 index 0000000..2c47128 --- /dev/null +++ b/backend/db.sqlite3 diff --git a/backend/manage.py b/backend/manage.py new file mode 100644 index 0000000..b97917f --- /dev/null +++ b/backend/manage.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == '__main__': + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'EcoAlert.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) diff --git a/backend/media/article_images/1509985507176178258.jpg b/backend/media/article_images/1509985507176178258.jpg Binary files differnew file mode 100644 index 0000000..6489ea3 --- /dev/null +++ b/backend/media/article_images/1509985507176178258.jpg diff --git a/backend/media/article_images/329116.jpg b/backend/media/article_images/329116.jpg Binary files differnew file mode 100644 index 0000000..de52fca --- /dev/null +++ b/backend/media/article_images/329116.jpg diff --git a/backend/media/article_images/yRVeczP.png b/backend/media/article_images/yRVeczP.png Binary files differnew file mode 100644 index 0000000..f742843 --- /dev/null +++ b/backend/media/article_images/yRVeczP.png diff --git a/backend/media/article_images/yRVeczP_AGQSxgn.png b/backend/media/article_images/yRVeczP_AGQSxgn.png Binary files differnew file mode 100644 index 0000000..f742843 --- /dev/null +++ b/backend/media/article_images/yRVeczP_AGQSxgn.png diff --git a/backend/media/article_images/yRVeczP_GKG4Obp.png b/backend/media/article_images/yRVeczP_GKG4Obp.png Binary files differnew file mode 100644 index 0000000..f742843 --- /dev/null +++ b/backend/media/article_images/yRVeczP_GKG4Obp.png diff --git a/backend/media/article_images/yRVeczP_azCHAvW.png b/backend/media/article_images/yRVeczP_azCHAvW.png Binary files differnew file mode 100644 index 0000000..f742843 --- /dev/null +++ b/backend/media/article_images/yRVeczP_azCHAvW.png diff --git a/backend/media/article_images/zagryazneniye-vody_3.jpg b/backend/media/article_images/zagryazneniye-vody_3.jpg Binary files differnew file mode 100644 index 0000000..a13481a --- /dev/null +++ b/backend/media/article_images/zagryazneniye-vody_3.jpg diff --git a/backend/media/avatars/Odnoklassniki.svg.png b/backend/media/avatars/Odnoklassniki.svg.png Binary files differnew file mode 100644 index 0000000..8694f9d --- /dev/null +++ b/backend/media/avatars/Odnoklassniki.svg.png diff --git a/backend/media/avatars/yRVeczP.png b/backend/media/avatars/yRVeczP.png Binary files differnew file mode 100644 index 0000000..f742843 --- /dev/null +++ b/backend/media/avatars/yRVeczP.png |