@@ -1,5 +0,0 @@ | |||||
from django.apps import AppConfig | |||||
class ApiConfig(AppConfig): | |||||
name = 'api' |
@@ -1,35 +0,0 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# Generated by Django 1.9 on 2015-12-18 09:18 | |||||
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): | |||||
initial = True | |||||
dependencies = [ | |||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL), | |||||
] | |||||
operations = [ | |||||
migrations.CreateModel( | |||||
name='Site', | |||||
fields=[ | |||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |||||
('created', models.DateTimeField(auto_now_add=True, verbose_name='created')), | |||||
('modified', models.DateTimeField(auto_now=True, verbose_name='modified')), | |||||
('name', models.CharField(max_length=255)), | |||||
('password_length', models.IntegerField()), | |||||
('password_type', models.CharField(max_length=255)), | |||||
('counter', models.IntegerField(default=1)), | |||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), | |||||
], | |||||
options={ | |||||
'abstract': False, | |||||
}, | |||||
), | |||||
] |
@@ -1,18 +0,0 @@ | |||||
from django.db import models | |||||
from django.contrib.auth.models import User | |||||
class DateMixin(models.Model): | |||||
created = models.DateTimeField(auto_now_add=True, verbose_name='created') | |||||
modified = models.DateTimeField(auto_now=True, verbose_name='modified') | |||||
class Meta: | |||||
abstract = True | |||||
class Site(DateMixin): | |||||
user = models.ForeignKey(User, on_delete=models.CASCADE) | |||||
name = models.CharField(max_length=255) | |||||
password_length = models.IntegerField() | |||||
password_type = models.CharField(max_length=255) | |||||
counter = models.IntegerField(default=1) |
@@ -1,6 +0,0 @@ | |||||
from rest_framework import permissions | |||||
class IsOwner(permissions.IsAuthenticated): | |||||
def has_object_permission(self, request, view, obj): | |||||
return obj.user == request.user |
@@ -1,9 +0,0 @@ | |||||
from rest_framework import serializers | |||||
from api.models import Site | |||||
class SiteSerializer(serializers.ModelSerializer): | |||||
class Meta: | |||||
model = Site | |||||
fields = ('user', 'name', 'password_length', 'password_type', 'counter', 'created', 'modified') |
@@ -1,30 +0,0 @@ | |||||
import factory | |||||
from api import models | |||||
class UserFactory(factory.DjangoModelFactory): | |||||
class Meta: | |||||
model = models.User | |||||
username = factory.Sequence(lambda n: 'username{0}'.format(n)) | |||||
first_name = factory.Faker('first_name') | |||||
last_name = factory.Faker('last_name') | |||||
email = factory.LazyAttribute(lambda a: '{0}.{1}@oslab.fr'.format(a.first_name, a.last_name).lower()) | |||||
password = factory.PostGenerationMethodCall('set_password', 'password') | |||||
is_staff = False | |||||
class AdminFactory(UserFactory): | |||||
is_staff = True | |||||
class SiteFactory(factory.DjangoModelFactory): | |||||
class Meta: | |||||
model = models.Site | |||||
user = factory.SubFactory(UserFactory) | |||||
name = 'facebook' | |||||
password_length = 12 | |||||
password_type = 'strong' | |||||
counter = 1 |
@@ -1,46 +0,0 @@ | |||||
from rest_framework.test import APITestCase, APIClient | |||||
from api import models | |||||
from api.tests import factories | |||||
class LogoutApiTestCase(APITestCase): | |||||
def test_get_sites_403(self): | |||||
response = self.client.get('/api/sites/') | |||||
self.assertEqual(403, response.status_code) | |||||
class LoginApiTestCase(APITestCase): | |||||
def setUp(self): | |||||
self.user = factories.UserFactory() | |||||
self.client = APIClient() | |||||
self.client.force_authenticate(user=self.user) | |||||
def test_get_empty_sites(self): | |||||
request = self.client.get('/api/sites/') | |||||
self.assertEqual(0, len(request.data['results'])) | |||||
def test_retrieve_its_own_sites(self): | |||||
site = factories.SiteFactory(user=self.user) | |||||
request = self.client.get('/api/sites/') | |||||
self.assertEqual(1, len(request.data['results'])) | |||||
self.assertEqual(site.name, request.data['results'][0]['name']) | |||||
def test_cant_retrieve_other_sites(self): | |||||
not_my_site = factories.SiteFactory(user=factories.UserFactory()) | |||||
request = self.client.get('/api/sites/%s/' % not_my_site.id) | |||||
self.assertEqual(404, request.status_code) | |||||
def test_delete_its_own_sites(self): | |||||
site = factories.SiteFactory(user=self.user) | |||||
self.assertEqual(1, models.Site.objects.all().count()) | |||||
request = self.client.delete('/api/sites/%s/' % site.id) | |||||
self.assertEqual(204, request.status_code) | |||||
self.assertEqual(0, models.Site.objects.all().count()) | |||||
def test_cant_delete_other_site(self): | |||||
not_my_site = factories.SiteFactory(user=factories.UserFactory()) | |||||
self.assertEqual(1, models.Site.objects.all().count()) | |||||
request = self.client.delete('/api/sites/%s/' % not_my_site.id) | |||||
self.assertEqual(404, request.status_code) | |||||
self.assertEqual(1, models.Site.objects.all().count()) |
@@ -1,11 +0,0 @@ | |||||
from django.conf.urls import include, url | |||||
from rest_framework import routers | |||||
from api import views | |||||
router = routers.DefaultRouter() | |||||
router.register(r'sites', views.SiteViewSet, base_name='sites') | |||||
urlpatterns = [ | |||||
url(r'^', include(router.urls)), | |||||
] |
@@ -1,13 +0,0 @@ | |||||
from rest_framework import viewsets | |||||
from api import models | |||||
from api.permissions import IsOwner | |||||
from api.serializers import SiteSerializer | |||||
class SiteViewSet(viewsets.ModelViewSet): | |||||
serializer_class = SiteSerializer | |||||
permission_classes = (IsOwner,) | |||||
def get_queryset(self): | |||||
return models.Site.objects.filter(user=self.request.user) |
@@ -1,3 +0,0 @@ | |||||
[DJANGO] | |||||
secret_key = 4f(fn@)x_512yrs_yc063fw12&bg7h83gehxkg@9*bvk8g^zmf | |||||
@@ -1,111 +0,0 @@ | |||||
import os | |||||
from smartconfigparser import Config | |||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | |||||
CONFIG_PATH = os.path.join(BASE_DIR, 'config') | |||||
if not os.path.exists(CONFIG_PATH): | |||||
os.makedirs(CONFIG_PATH) | |||||
CONFIG_FILE = os.path.join(CONFIG_PATH, 'config.ini') | |||||
config = Config() | |||||
config.read(CONFIG_FILE) | |||||
try: | |||||
SECRET_KEY = config.get('DJANGO', 'SECRET_KEY') | |||||
except: | |||||
print('SECRET_KEY not found! Generating a new one...') | |||||
import random | |||||
SECRET_KEY = "".join([random.choice("abcdefghijklmnopqrstuvwxyz0123456789!@#$^&*(-_=+)") for i in range(50)]) | |||||
if not config.has_section('DJANGO'): | |||||
config.add_section('DJANGO') | |||||
config.set('DJANGO', 'SECRET_KEY', SECRET_KEY) | |||||
with open(CONFIG_FILE, 'wt') as f: | |||||
config.write(f) | |||||
DEBUG = config.getboolean('DJANGO', 'DEBUG', False) | |||||
ALLOWED_HOSTS = config.getlist('DJANGO', 'ALLOWED_HOSTS', ['localhost', '127.0.0.1', '*.oslab.fr']) | |||||
INSTALLED_APPS = [ | |||||
'api.apps.ApiConfig', | |||||
'django.contrib.admin', | |||||
'django.contrib.auth', | |||||
'django.contrib.contenttypes', | |||||
'django.contrib.sessions', | |||||
'django.contrib.messages', | |||||
'django.contrib.staticfiles', | |||||
'rest_framework' | |||||
] | |||||
MIDDLEWARE_CLASSES = [ | |||||
'django.middleware.security.SecurityMiddleware', | |||||
'django.contrib.sessions.middleware.SessionMiddleware', | |||||
'django.middleware.common.CommonMiddleware', | |||||
'django.middleware.csrf.CsrfViewMiddleware', | |||||
'django.contrib.auth.middleware.AuthenticationMiddleware', | |||||
'django.contrib.auth.middleware.SessionAuthenticationMiddleware', | |||||
'django.contrib.messages.middleware.MessageMiddleware', | |||||
'django.middleware.clickjacking.XFrameOptionsMiddleware', | |||||
] | |||||
ROOT_URLCONF = 'lesspass.urls' | |||||
TEMPLATES = [ | |||||
{ | |||||
'BACKEND': 'django.template.backends.django.DjangoTemplates', | |||||
'DIRS': [], | |||||
'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 = 'lesspass.wsgi.application' | |||||
DATABASES = { | |||||
'default': { | |||||
'ENGINE': 'django.db.backends.sqlite3', | |||||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), | |||||
} | |||||
} | |||||
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', | |||||
}, | |||||
] | |||||
LANGUAGE_CODE = 'en-us' | |||||
TIME_ZONE = 'UTC' | |||||
USE_I18N = True | |||||
USE_L10N = True | |||||
USE_TZ = True | |||||
STATIC_URL = '/static/' | |||||
REST_FRAMEWORK = { | |||||
'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAuthenticated',), | |||||
'PAGE_SIZE': 100, | |||||
'TEST_REQUEST_DEFAULT_FORMAT': 'json' | |||||
} |
@@ -1,7 +0,0 @@ | |||||
from django.conf.urls import include, url | |||||
from django.contrib import admin | |||||
urlpatterns = [ | |||||
url(r'^admin/', admin.site.urls), | |||||
url(r'^api/', include('api.urls')), | |||||
] |
@@ -1,7 +0,0 @@ | |||||
import os | |||||
from django.core.wsgi import get_wsgi_application | |||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lesspass.settings") | |||||
application = get_wsgi_application() |
@@ -1,10 +0,0 @@ | |||||
#!/usr/bin/env python | |||||
import os | |||||
import sys | |||||
if __name__ == "__main__": | |||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lesspass.settings") | |||||
from django.core.management import execute_from_command_line | |||||
execute_from_command_line(sys.argv) |
@@ -1,2 +0,0 @@ | |||||
-r requirements.txt | |||||
factory-boy==2.6.0 |
@@ -1,3 +0,0 @@ | |||||
Django==1.9 | |||||
djangorestframework==3.3.2 | |||||
smartconfigparser==0.1.1 |