diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000000000000000000000000000000000000..8ca541fdb804d9527bcd9f76f57a778e5fa60c41 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,31 @@ +version: 2 +jobs: + build: + working_directory: ~/kszkepzes + docker: + - image: circleci/python:3.6.4 + steps: + - checkout + - run: sudo chown -R circleci:circleci /usr/local/bin + - run: sudo chown -R circleci:circleci /usr/local/lib/python3.6/site-packages + - restore_cache: + key: deps9-{{ .Branch }}-{{ checksum "Pipfile.lock" }} + - run: + command: | + sudo pip install -r requirements/development.txt + - save_cache: + key: deps9-{{ .Branch }}-{{ checksum "Pipfile.lock" }} + paths: + - ".venv" + - "/usr/local/bin" + - "/usr/local/lib/python3.6/site-packages" + - run: + command: | + flake8 --max-line-length=125 --exclude=src/kszkepzes,migrations + python src/manage.py migrate + python src/manage.py test + - store_test_results: + path: test-results + - store_artifacts: + path: test-results + destination: tr1 diff --git a/README.md b/README.md index 38d506ef0bdc041ae74ccf9d5f01de0ca5fac7d7..ab80fea2101139b907870729841b21df134d6782 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ [](https://travis-ci.org/DevTeamSCH/kszkepzes) +[](https://circleci.com/gh/DevTeamSCH/kszkepzes/tree/master) + ## KĂśvetelmĂŠnyek 1. python3.5 diff --git a/requirements/base.in b/requirements/base.in index 442a003143dbc7afde0dac219361683a666615e2..d38f35becf4d4f536496f0838654018c439ffb26 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -1,3 +1,4 @@ -Django==1.11.5 -djangorestframework==3.6.4 +Django==2.0.1 +djangorestframework==3.7.7 django-social-authsch==0.1 +django-solo==1.1.3 diff --git a/requirements/development.in b/requirements/development.in index a947995cb351da9beb9a48c88383fcfba97354f2..d80fc6250c3504682e90f62fdf9abfed415f824c 100644 --- a/requirements/development.in +++ b/requirements/development.in @@ -1,4 +1,5 @@ -r base.in flake8==3.4.1 pip-tools==1.9.0 -django-extensions==1.9.1 +django-extensions==1.9.9 +python-language-server==0.13.0 diff --git a/requirements/development.txt b/requirements/development.txt index 68babd8a27fcd1363a821912246752fa0a828d66..2806f075fd5fcbc4a0f09bead0d99fff22a3401b 100644 --- a/requirements/development.txt +++ b/requirements/development.txt @@ -7,25 +7,38 @@ certifi==2017.7.27.1 # via requests chardet==3.0.4 # via requests click==6.7 # via pip-tools +configparser==3.5.0 # via python-language-server defusedxml==0.5.0 # via python3-openid, social-auth-core -django-extensions==1.9.1 +django-extensions==1.9.9 django-social-authsch==0.1 -django==1.11.5 -djangorestframework==3.6.4 +django-solo==1.1.3 +django==2.0.1 +djangorestframework==3.7.7 first==2.0.1 # via pip-tools flake8==3.4.1 +future==0.16.0 # via python-language-server idna==2.6 # via requests -mccabe==0.6.1 # via flake8 +jedi==0.11.1 # via python-language-server +json-rpc==1.10.8 # via python-language-server +mccabe==0.6.1 # via flake8, python-language-server oauthlib==2.0.6 # via requests-oauthlib, social-auth-core +parso==0.1.1 # via jedi pip-tools==1.9.0 -pycodestyle==2.3.1 # via flake8 -pyflakes==1.5.0 # via flake8 +pluggy==0.6.0 # via python-language-server +pycodestyle==2.3.1 # via flake8, python-language-server +pydocstyle==2.1.1 # via python-language-server +pyflakes==1.5.0 # via flake8, python-language-server pyjwt==1.5.3 # via social-auth-core +python-language-server==0.13.0 python3-openid==3.1.0 # via social-auth-core pytz==2017.2 # via django requests-oauthlib==0.8.0 # via social-auth-core requests==2.18.4 # via requests-oauthlib, social-auth-core -six==1.10.0 # via django-extensions, pip-tools, social-auth-app-django, social-auth-core +rope==0.10.7 # via python-language-server +six==1.10.0 # via django-extensions, pip-tools, pydocstyle, social-auth-app-django, social-auth-core +snowballstemmer==1.2.1 # via pydocstyle social-auth-app-django==2.0.0 # via django-social-authsch social-auth-core==1.5.0 # via django-social-authsch, social-auth-app-django +typing==3.6.4 # via django-extensions urllib3==1.22 # via requests +yapf==0.20.1 # via python-language-server diff --git a/requirements/production.in b/requirements/production.in new file mode 100644 index 0000000000000000000000000000000000000000..00a73eea0fce88f6ffa4c793be6b1966a47d95b8 --- /dev/null +++ b/requirements/production.in @@ -0,0 +1,2 @@ +-r base.in +gunicorn==19.7.1 diff --git a/requirements/production.txt b/requirements/production.txt new file mode 100644 index 0000000000000000000000000000000000000000..31199b03b9b308ed7759df6e635f9971d07e2ed5 --- /dev/null +++ b/requirements/production.txt @@ -0,0 +1,25 @@ +# +# This file is autogenerated by pip-compile +# To update, run: +# +# pip-compile --output-file production.txt production.in +# +certifi==2018.1.18 # via requests +chardet==3.0.4 # via requests +defusedxml==0.5.0 # via python3-openid, social-auth-core +django-social-authsch==0.1 +django-solo==1.1.3 +django==2.0.1 +djangorestframework==3.7.7 +gunicorn==19.7.1 +idna==2.6 # via requests +oauthlib==2.0.6 # via requests-oauthlib, social-auth-core +pyjwt==1.5.3 # via social-auth-core +python3-openid==3.1.0 # via social-auth-core +pytz==2017.3 # via django +requests-oauthlib==0.8.0 # via social-auth-core +requests==2.18.4 # via requests-oauthlib, social-auth-core +six==1.11.0 # via social-auth-app-django, social-auth-core +social-auth-app-django==2.1.0 # via django-social-authsch +social-auth-core==1.6.0 # via django-social-authsch, social-auth-app-django +urllib3==1.22 # via requests diff --git a/src/account/admin.py b/src/account/admin.py index b9e5817dfac078d71887a8d90fdda504257bb88a..3977099f0b803d0214933039309e11ae5162b5bf 100644 --- a/src/account/admin.py +++ b/src/account/admin.py @@ -1,5 +1,6 @@ from django.contrib import admin from . import models +from solo.admin import SingletonModelAdmin @admin.register(models.Profile) @@ -14,3 +15,4 @@ class ProfileAdmin(admin.ModelAdmin): # Register your models here. admin.site.register(models.GroupChoice) +admin.site.register(models.Deadline, SingletonModelAdmin) diff --git a/src/account/auth_pipeline.py b/src/account/auth_pipeline.py new file mode 100644 index 0000000000000000000000000000000000000000..b1918c536d09e7b1de94f3c63c249ed6eff9e5f2 --- /dev/null +++ b/src/account/auth_pipeline.py @@ -0,0 +1,11 @@ +from django.core import exceptions + +from . import models + + +def create_profile(backend, user, response, *args, **kwargs): + if backend.name == 'authsch': + try: + user.profile + except exceptions.ObjectDoesNotExist: + models.Profile.objects.create(user=user) diff --git a/src/account/migrations/0011_deadline.py b/src/account/migrations/0011_deadline.py new file mode 100644 index 0000000000000000000000000000000000000000..e88ed12d346eefbc0226895bd725d1bc49541928 --- /dev/null +++ b/src/account/migrations/0011_deadline.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2018-01-25 18:42 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('account', '0010_auto_20180124_1929'), + ] + + operations = [ + migrations.CreateModel( + name='Deadline', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('deadline', models.DateField()), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/src/account/migrations/0012_auto_20180125_1957.py b/src/account/migrations/0012_auto_20180125_1957.py new file mode 100644 index 0000000000000000000000000000000000000000..92845d1c75bcd23abaf68710d8c4bf93162fc7dd --- /dev/null +++ b/src/account/migrations/0012_auto_20180125_1957.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2018-01-25 18:57 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('account', '0011_deadline'), + ] + + operations = [ + migrations.AlterField( + model_name='deadline', + name='deadline', + field=models.DateField(null=True), + ), + ] diff --git a/src/account/migrations/0013_auto_20180203_2007.py b/src/account/migrations/0013_auto_20180203_2007.py new file mode 100644 index 0000000000000000000000000000000000000000..8ac041e4d538e265f8f47fdaae0960ed54edd6b2 --- /dev/null +++ b/src/account/migrations/0013_auto_20180203_2007.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0.1 on 2018-02-03 19:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('account', '0012_auto_20180125_1957'), + ] + + operations = [ + migrations.AlterField( + model_name='profile', + name='join_date', + field=models.DateTimeField(auto_now=True), + ), + ] diff --git a/src/account/migrations/0014_auto_20180203_2010.py b/src/account/migrations/0014_auto_20180203_2010.py new file mode 100644 index 0000000000000000000000000000000000000000..0ad3c0554ec582ff41cc7536f02287c77f3fdb66 --- /dev/null +++ b/src/account/migrations/0014_auto_20180203_2010.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0.1 on 2018-02-03 19:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('account', '0013_auto_20180203_2007'), + ] + + operations = [ + migrations.AlterField( + model_name='deadline', + name='deadline', + field=models.DateTimeField(null=True), + ), + ] diff --git a/src/account/migrations/0015_auto_20180203_2014.py b/src/account/migrations/0015_auto_20180203_2014.py new file mode 100644 index 0000000000000000000000000000000000000000..e823387e6830f772c4651f21c876c0ae0534f4cc --- /dev/null +++ b/src/account/migrations/0015_auto_20180203_2014.py @@ -0,0 +1,23 @@ +# Generated by Django 2.0.1 on 2018-02-03 19:14 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('account', '0014_auto_20180203_2010'), + ] + + operations = [ + migrations.AddField( + model_name='profile', + name='updated_at', + field=models.DateTimeField(auto_now=True), + ), + migrations.AlterField( + model_name='profile', + name='join_date', + field=models.DateTimeField(auto_now_add=True), + ), + ] diff --git a/src/account/migrations/0016_auto_20180203_2022.py b/src/account/migrations/0016_auto_20180203_2022.py new file mode 100644 index 0000000000000000000000000000000000000000..86c2ae6dc33f0c16b7e8f1ea9489baf1e3d9cdd6 --- /dev/null +++ b/src/account/migrations/0016_auto_20180203_2022.py @@ -0,0 +1,23 @@ +# Generated by Django 2.0.1 on 2018-02-03 19:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('account', '0015_auto_20180203_2014'), + ] + + operations = [ + migrations.AlterField( + model_name='profile', + name='motivation', + field=models.TextField(blank=True, default=''), + ), + migrations.AlterField( + model_name='profile', + name='nick', + field=models.CharField(blank=True, default='', max_length=15), + ), + ] diff --git a/src/account/models.py b/src/account/models.py index 9c9f6825eabda79f1ca0363ced2c56c691959299..da900ea17f179da18d9c525722bf52c203cea34d 100644 --- a/src/account/models.py +++ b/src/account/models.py @@ -1,5 +1,6 @@ from django.db import models from django.contrib.auth.models import User +from solo.models import SingletonModel class GroupChoice(models.Model): @@ -18,13 +19,19 @@ class GroupChoice(models.Model): class Profile(models.Model): - join_date = models.DateField(auto_now=True) + join_date = models.DateTimeField(auto_now_add=True, editable=False) + updated_at = models.DateTimeField(auto_now=True, editable=False) user = models.OneToOneField(User, related_name='profile', on_delete=models.CASCADE) - motivation = models.TextField(null=True) - nick = models.CharField(max_length=15, blank=True, null=True) + # TODO: Change the default to json render side + motivation = models.TextField(blank=True, default='') + nick = models.CharField(max_length=15, blank=True, default='') signed = models.BooleanField(default=False, null=False) groups = models.ManyToManyField(GroupChoice, related_name='profiles') # Homeworks=models.ForeignKey(Homework) def __str__(self): return self.user.username + + +class Deadline(SingletonModel): + deadline = models.DateTimeField(null=True) diff --git a/src/account/serializers.py b/src/account/serializers.py index 92a0828d55c5b8cd3a575ba0d16cb9f4711f87c8..bee56c0464103291cef16fc206fcb781b6edc0b1 100644 --- a/src/account/serializers.py +++ b/src/account/serializers.py @@ -10,7 +10,19 @@ class ChoiceSerializer(serializers.ModelSerializer): class ProfileSerializer(serializers.ModelSerializer): groups = serializers.SlugRelatedField(many=True, slug_field="choice", queryset=models.GroupChoice.objects.all()) + updated_at = serializers.DateTimeField(read_only=True) + signed = serializers.BooleanField() class Meta: model = models.Profile - fields = ('id', 'join_date', 'user', 'nick', 'motivation', 'signed', 'groups') + fields = ('id', 'join_date', 'updated_at', 'user', 'nick', 'motivation', 'signed', 'groups') + + def validate(self, data): + deadline = models.Deadline.get_solo().deadline + if deadline is None: + return data + + if data['signed'] is True and data['updated_at'] > deadline: + raise serializers.ValidationError("You cannot join after the deadline") + + return data diff --git a/src/account/views.py b/src/account/views.py index 58c405059a1c21a80a62d1b1de6e658277a0f350..fde64a8529b11c5561318014a5305b2ce5aef8df 100644 --- a/src/account/views.py +++ b/src/account/views.py @@ -16,6 +16,8 @@ class ProfileViewSet(viewsets.ModelViewSet): if user.has_perm(permissions.IsAdminUser): return models.Profile.objects.all() + return models.Profile.objects.filter(pk=user.profile.id) + @list_route(methods=['get']) def me(self, request): serializer = self.serializer_class(request.user.profile) diff --git a/src/homework/admin.py b/src/homework/admin.py index 38fed616d8ac56d7290d795fd12ada5d18b4fadd..1ba19837f05c7a96fdde7a569326c8dfe5cb00e9 100644 --- a/src/homework/admin.py +++ b/src/homework/admin.py @@ -3,4 +3,4 @@ from . import models # Register your models here. admin.site.register(models.Solution) -admin.site.register(models.Task) \ No newline at end of file +admin.site.register(models.Task) diff --git a/src/homework/migrations/0004_auto_20180125_1817.py b/src/homework/migrations/0004_auto_20180125_1817.py new file mode 100644 index 0000000000000000000000000000000000000000..9693462cf1df61aa81b3afd1810968e5b8ee444b --- /dev/null +++ b/src/homework/migrations/0004_auto_20180125_1817.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2018-01-25 17:17 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('homework', '0003_auto_20180124_1818'), + ] + + operations = [ + migrations.AlterField( + model_name='solution', + name='created_by', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/src/homework/migrations/0005_auto_20180126_0135.py b/src/homework/migrations/0005_auto_20180126_0135.py new file mode 100644 index 0000000000000000000000000000000000000000..0155be9f4f3740b5aca421362a0b57b429fcd737 --- /dev/null +++ b/src/homework/migrations/0005_auto_20180126_0135.py @@ -0,0 +1,20 @@ +# Generated by Django 2.0.1 on 2018-01-26 00:35 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('homework', '0004_auto_20180125_1817'), + ] + + operations = [ + migrations.AlterField( + model_name='task', + name='created_by', + field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/src/homework/models.py b/src/homework/models.py index 0e94c27c497efe4e6dd8eed001356a8b5b0a27b5..5a8b2026a6deb3909a5129278e4695b58bcf47ba 100644 --- a/src/homework/models.py +++ b/src/homework/models.py @@ -21,11 +21,11 @@ def validate_deadline(date): # raise ValidationError(_('Please keep filesize under' + __MAX_UPLOAD_SIZE)) class Task(models.Model): - title = models.CharField(max_length=150, ) - date = models.DateTimeField(auto_now_add=True, editable=False, ) - deadline = models.DateTimeField(validators=[validate_deadline], ) + title = models.CharField(max_length=150) + date = models.DateTimeField(auto_now_add=True, editable=False) + deadline = models.DateTimeField(validators=[validate_deadline]) text = models.TextField() - created_by = models.ForeignKey(User, ) + created_by = models.ForeignKey(User, on_delete=models.DO_NOTHING) files = models.FileField( validators=[validators.FileExtensionValidator( 'image/png', @@ -48,11 +48,11 @@ class Task(models.Model): class Solution(models.Model): - task = models.ForeignKey(Task, related_name='task_solution', on_delete=models.CASCADE, ) + task = models.ForeignKey(Task, related_name='task_solution', on_delete=models.CASCADE) # student = models.ForeignKey(account.models.Profile, related_name='student_solution', on_delete=models.CASCADE) - date = models.DateTimeField(auto_now_add=True, editable=False, ) - ready = models.BooleanField(default=False, ) #if(Soulution.date <= Task.deadline) - accepted = models.BooleanField(default=False, ) + date = models.DateTimeField(auto_now_add=True, editable=False) + ready = models.BooleanField(default=False) # if(Soulution.date <= Task.deadline) + accepted = models.BooleanField(default=False) files = models.FileField( validators=[validators.FileExtensionValidator( 'image/png', @@ -61,7 +61,7 @@ class Solution(models.Model): )], blank=True, ) - created_by = models.ForeignKey(User, ) + created_by = models.ForeignKey(User, on_delete=models.CASCADE) # files = myfields.RestrictedFileField( # content_types=['image/png', 'image/jpeg', 'application/zip'], # max_upload_size=MAX_UPLOAD_SIZE, diff --git a/src/homework/permissions.py b/src/homework/permissions.py index 061b11cf236e09ab32d9a48a1e22e854df50f0f4..659c3a60c87ea61abb684a8c0e6f91b568685431 100644 --- a/src/homework/permissions.py +++ b/src/homework/permissions.py @@ -8,11 +8,7 @@ class IsStaffOrReadOnly(BasePermission): """ def has_permission(self, request, view): - return ( - request.method in SAFE_METHODS or - request.user and - request.user.is_staff - ) + return request.method in SAFE_METHODS or request.user and request.user.is_staff class IsAuthenticatedOrReadOnly(BasePermission): @@ -21,11 +17,7 @@ class IsAuthenticatedOrReadOnly(BasePermission): """ def has_permission(self, request, view): - return ( - request.method in SAFE_METHODS or - request.user and - request.user.is_authenticated - ) + return request.method in SAFE_METHODS or request.user and request.user.is_authenticated class IsStaffOrReadOnlyForAuthenticated(BasePermission): @@ -33,13 +25,8 @@ class IsStaffOrReadOnlyForAuthenticated(BasePermission): """ The request is authenticated as a staff, or is a read-only request for authenticated. """ - def has_permission(self, request, view): - return ( - request.user.is_staff or - request.method in SAFE_METHODS and - request.user.is_authenticated - ) + return request.user.is_staff or request.method in SAFE_METHODS and request.user.is_authenticated class IsStaffUser(BasePermission): @@ -50,3 +37,4 @@ class IsStaffUser(BasePermission): def has_permission(self, request, view): return request.user.is_staff + \ No newline at end of file diff --git a/src/homework/tests.py b/src/homework/tests.py index 7ce503c2dd97ba78597f6ff6e4393132753573f6..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 --- a/src/homework/tests.py +++ b/src/homework/tests.py @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/src/kszkepzes/settings/__init__.py b/src/kszkepzes/settings/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/kszkepzes/settings.py b/src/kszkepzes/settings/base.py similarity index 85% rename from src/kszkepzes/settings.py rename to src/kszkepzes/settings/base.py index 5c53612e437be6058af830883882a6f066779668..91ebe6e357cb0757895d7854854c35036acf4227 100644 --- a/src/kszkepzes/settings.py +++ b/src/kszkepzes/settings/base.py @@ -40,10 +40,12 @@ INSTALLED_APPS = [ 'django_extensions', 'rest_framework', 'social_django', + 'solo', 'authsch', 'homework', 'account', 'stats', + 'news', ] MIDDLEWARE = [ @@ -113,11 +115,24 @@ AUTHENTICATION_BACKENDS = [ 'django.contrib.auth.backends.ModelBackend', ] +SOCIAL_AUTH_PIPELINE = ( + 'social_core.pipeline.social_auth.social_details', + 'social_core.pipeline.social_auth.social_uid', + 'social_core.pipeline.social_auth.auth_allowed', + 'social_core.pipeline.social_auth.social_user', + 'social_core.pipeline.user.get_username', + 'social_core.pipeline.user.create_user', + 'account.auth_pipeline.create_profile', + 'social_core.pipeline.social_auth.associate_user', + 'social_core.pipeline.social_auth.load_extra_data', + 'social_core.pipeline.user.user_details', +) + SOCIAL_AUTH_AUTHSCH_KEY = os.getenv('AUTHSCH_KEY') SOCIAL_AUTH_AUTHSCH_SECRET = os.getenv('AUTHSCH_SECRET') SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/' LOGIN_URL = "login/authsch/" - +LOGOUT_REDIRECT_URL = '/' # Internationalization # https://docs.djangoproject.com/en/1.11/topics/i18n/ @@ -136,4 +151,4 @@ USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.11/howto/static-files/ -STATIC_URL = '/static/' +STATIC_URL = '/django-static/' diff --git a/src/kszkepzes/settings/local.py b/src/kszkepzes/settings/local.py new file mode 100644 index 0000000000000000000000000000000000000000..9b5ed21c9e3f65438f966db7f1913bc34b7ffa97 --- /dev/null +++ b/src/kszkepzes/settings/local.py @@ -0,0 +1 @@ +from .base import * diff --git a/src/kszkepzes/settings/production.py b/src/kszkepzes/settings/production.py new file mode 100644 index 0000000000000000000000000000000000000000..ebf105027c4fcc9bd936482fd349dc1d7f526323 --- /dev/null +++ b/src/kszkepzes/settings/production.py @@ -0,0 +1,28 @@ +from .base import * + +DEBUG = False + +ALLOWED_HOSTS = ['*'] + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': os.getenv('DB_NAME', 'kszkepzes'), + 'USER': os.getenv('DB_USER'), + 'PASSWORD': os.getenv('DB_PASSWORD'), + 'HOST': os.getenv('DB_HOST', 'localhost'), + 'PORT': os.getenv('DB_PORT', 5432), + } +} + + +REST_FRAMEWORK = { + 'DEFAULT_RENDERER_CLASSES': ( + 'rest_framework.renderers.JSONRenderer', + ), + 'DEFAULT_PARSER_CLASSES': ( + 'rest_framework.parsers.JSONParser', + ) +} + +STATIC_ROOT = os.path.join(BASE_DIR, 'static_collected') diff --git a/src/kszkepzes/urls.py b/src/kszkepzes/urls.py index cb9bbcdc434a5db23b90606ebf69b6744b115a65..b696e393918a0e73867aae8dd1712ff633e77b4a 100644 --- a/src/kszkepzes/urls.py +++ b/src/kszkepzes/urls.py @@ -1,25 +1,14 @@ -"""kszkepzes URL Configuration - -The `urlpatterns` list routes URLs to views. For more information please see: - https://docs.djangoproject.com/en/1.11/topics/http/urls/ -Examples: -Function views - 1. Add an import: from my_app import views - 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') -Class-based views - 1. Add an import: from other_app.views import Home - 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') -Including another URLconf - 1. Import the include() function: from django.conf.urls import url, include - 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) -""" from django.conf.urls import url, include from django.contrib import admin +from django.contrib.auth import views as auth_views urlpatterns = [ url(r'^admin/', admin.site.urls), - url('', include('social_django.urls', namespace='social')), + url(r'^api/v1/', include('social_django.urls', namespace='social')), url(r'^api/v1/homework/', include('homework.urls')), url(r'^api/v1/', include('stats.urls')), url(r'^api/v1/', include('account.urls')), + url(r'^api/v1/', include('news.urls')), + + url(r'^api/v1/logout/$', auth_views.LogoutView.as_view(), name='logout'), ] diff --git a/src/kszkepzes/wsgi.py b/src/kszkepzes/wsgi.py index 693ce0202c598857f3c85898ceb1494ad735381e..12023b6a78e7c9bbb5cc7e48d9d4f63b9eba7b3e 100644 --- a/src/kszkepzes/wsgi.py +++ b/src/kszkepzes/wsgi.py @@ -11,6 +11,6 @@ import os from django.core.wsgi import get_wsgi_application -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "kszkepzes.settings") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "kszkepzes.settings.production") application = get_wsgi_application() diff --git a/src/manage.py b/src/manage.py index 68a31626ba48090be7d4cf5607bc718c974c6aff..e4402b7b44c4dde5fabcac097975a806d90b055f 100755 --- a/src/manage.py +++ b/src/manage.py @@ -3,7 +3,7 @@ import os import sys if __name__ == "__main__": - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "kszkepzes.settings") + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "kszkepzes.settings.local") try: from django.core.management import execute_from_command_line except ImportError: diff --git a/src/news/__init__.py b/src/news/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/news/admin.py b/src/news/admin.py new file mode 100644 index 0000000000000000000000000000000000000000..7f39d2fe12544dbc56abffe0abb6766e05fd843d --- /dev/null +++ b/src/news/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin +from .models import Article + +admin.site.register(Article) +# Register your models here. diff --git a/src/news/apps.py b/src/news/apps.py new file mode 100644 index 0000000000000000000000000000000000000000..5a7b92d0f844e1bd89c73e7bba369b07298ae70a --- /dev/null +++ b/src/news/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class NewsConfig(AppConfig): + name = 'news' diff --git a/src/news/migrations/0001_initial.py b/src/news/migrations/0001_initial.py new file mode 100644 index 0000000000000000000000000000000000000000..3e3bf0cd6b30767f0b17a436e2c1eede7b9061a7 --- /dev/null +++ b/src/news/migrations/0001_initial.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2017-11-28 19:55 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('account', '0002_auto_20171114_2144'), + ] + + operations = [ + migrations.CreateModel( + name='Article', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=200)), + ('text', models.TextField()), + ('date', models.DateTimeField()), + ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='author', to='account.Profile')), + ], + ), + ] diff --git a/src/news/migrations/0002_auto_20171220_1852.py b/src/news/migrations/0002_auto_20171220_1852.py new file mode 100644 index 0000000000000000000000000000000000000000..82274a5e164ffb466661b8358d3839ee44f9f78a --- /dev/null +++ b/src/news/migrations/0002_auto_20171220_1852.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2017-12-20 17:52 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('news', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='article', + name='date', + field=models.DateTimeField(auto_now_add=True), + ), + ] diff --git a/src/news/migrations/0003_auto_20180126_0135.py b/src/news/migrations/0003_auto_20180126_0135.py new file mode 100644 index 0000000000000000000000000000000000000000..744aef9118bc2963df22d62ea5af9c8230adf26c --- /dev/null +++ b/src/news/migrations/0003_auto_20180126_0135.py @@ -0,0 +1,29 @@ +# Generated by Django 2.0.1 on 2018-01-26 00:35 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('news', '0002_auto_20171220_1852'), + ] + + operations = [ + migrations.RenameField( + model_name='article', + old_name='date', + new_name='created_at', + ), + migrations.AddField( + model_name='article', + name='updated_at', + field=models.DateTimeField(auto_now=True), + ), + migrations.AlterField( + model_name='article', + name='author', + field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='author', to='account.Profile'), + ), + ] diff --git a/src/news/migrations/__init__.py b/src/news/migrations/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/news/models.py b/src/news/models.py new file mode 100644 index 0000000000000000000000000000000000000000..0714bf16b3c1e24f9d9da0b476e5f8bdb04f428d --- /dev/null +++ b/src/news/models.py @@ -0,0 +1,13 @@ +from django.db import models +from account.models import Profile + + +class Article(models.Model): + author = models.ForeignKey(Profile, related_name="author", on_delete=models.DO_NOTHING) + title = models.CharField(null=False, max_length=200) + text = models.TextField() + created_at = models.DateTimeField(auto_now_add=True, editable=False) + updated_at = models.DateTimeField(auto_now=True, editable=False) + + def __str__(self): + return self.title diff --git a/src/news/permissions.py b/src/news/permissions.py new file mode 100644 index 0000000000000000000000000000000000000000..8eca896872bb01b9a786a2d128b4feaa64e0a714 --- /dev/null +++ b/src/news/permissions.py @@ -0,0 +1,7 @@ +from rest_framework.permissions import BasePermission +from rest_framework.permissions import SAFE_METHODS + + +class IsStaffOrReadOnly(BasePermission): + def has_permission(self, request, view): + return request.user.is_staff or request.method in SAFE_METHODS diff --git a/src/news/serializers.py b/src/news/serializers.py new file mode 100644 index 0000000000000000000000000000000000000000..6da75f52b1e41c2bc99b1b3727c97cd6606b4453 --- /dev/null +++ b/src/news/serializers.py @@ -0,0 +1,8 @@ +from news.models import Article +from rest_framework import serializers + + +class ArticleListSerializer(serializers.ModelSerializer): + class Meta: + model = Article + fields = serializers.ALL_FIELDS diff --git a/src/news/tests.py b/src/news/tests.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/news/urls.py b/src/news/urls.py new file mode 100644 index 0000000000000000000000000000000000000000..d71ed82e9e76d7ee61aa6e91c0f8f868a28b1280 --- /dev/null +++ b/src/news/urls.py @@ -0,0 +1,8 @@ +from rest_framework import routers +from news import views + + +router = routers.DefaultRouter() +router.register(r'news', views.NewsViewSet) + +urlpatterns = router.urls diff --git a/src/news/views.py b/src/news/views.py new file mode 100644 index 0000000000000000000000000000000000000000..0264eddbaabcd57ab898134d039a30ac9911f75c --- /dev/null +++ b/src/news/views.py @@ -0,0 +1,10 @@ +from news.permissions import IsStaffOrReadOnly +from rest_framework import viewsets +from news.models import Article +from news.serializers import ArticleListSerializer + + +class NewsViewSet(viewsets.ModelViewSet): + serializer_class = ArticleListSerializer + permission_classes = [IsStaffOrReadOnly] + queryset = Article.objects.all() diff --git a/src/stats/urls.py b/src/stats/urls.py index 7c03811c1c72b2efe61eb9009f450a2047212956..ef0f4e2166c58ea7ceea950825e171cae29f6807 100644 --- a/src/stats/urls.py +++ b/src/stats/urls.py @@ -5,5 +5,4 @@ from . import views router = routers.DefaultRouter() router.register(r'events', views.KszkEventViewSet) -# app_name = 'stats' urlpatterns = router.urls