Compare commits
26 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
aa1e0912d2 | |
|
|
f0b5429070 | |
|
|
1a5582b625 | |
|
|
1cb80a8322 | |
|
|
6e61d83bbc | |
|
|
de22f24267 | |
|
|
4a6123edf0 | |
|
|
c4419bd483 | |
|
|
9afcd67eb3 | |
|
|
7ef2e263a2 | |
|
|
85bb627391 | |
|
|
8c1a3d9843 | |
|
|
e221d223ac | |
|
|
a9c1bf739f | |
|
|
fbd62622ee | |
|
|
e2c5274c53 | |
|
|
9da2611fbb | |
|
|
1d07048913 | |
|
|
89fc4b3099 | |
|
|
709df5fb90 | |
|
|
6a54b4d959 | |
|
|
344f71295c | |
|
|
1c84adcbda | |
|
|
88b75e1e9c | |
|
|
08f29d5cc6 | |
|
|
0b25a73127 |
|
|
@ -1,3 +1,4 @@
|
|||
# database
|
||||
|
||||
*.sqlite3
|
||||
*.sqlite3
|
||||
*.png
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
|
||||
# Music Service
|
||||
|
||||
## Basic Informations
|
||||
|
||||
Appliaction for sharing music and texts of songs once.
|
||||
|
||||
### Project Structure
|
||||
|
||||
```bash
|
||||
.
|
||||
├── account
|
||||
│ ├── admin.py
|
||||
│ ├── apps.py
|
||||
│ ├── models.py
|
||||
│ ├── serializers.py
|
||||
│ ├── tests.py
|
||||
│ └── views.py
|
||||
├── album
|
||||
│ ├── admin.py
|
||||
│ ├── apps.py
|
||||
│ ├── models.py
|
||||
│ ├── serializers.py
|
||||
│ ├── tests.py
|
||||
│ └── views.py
|
||||
├── comment
|
||||
│ ├── admin.py
|
||||
│ ├── apps.py
|
||||
│ ├── models.py
|
||||
│ ├── serializers.py
|
||||
│ ├── tests.py
|
||||
│ └── views.py
|
||||
├── playlist
|
||||
│ ├── admin.py
|
||||
│ ├── apps.py
|
||||
│ ├── models.py
|
||||
│ ├── serializers.py
|
||||
│ ├── tests.py
|
||||
│ └── views.py
|
||||
├── rating
|
||||
│ ├── admin.py
|
||||
│ ├── apps.py
|
||||
│ ├── models.py
|
||||
│ ├── serializers.py
|
||||
│ ├── tests.py
|
||||
│ └── views.py
|
||||
├── asgi.py
|
||||
├── settings.py
|
||||
├── urls.py
|
||||
├── utils.py
|
||||
└── wsgi.py
|
||||
```
|
||||
|
||||
### Shell / Bash Files
|
||||
|
||||
#### ../packages.sh
|
||||
|
||||
This file have every python virtual environment requirements for application run
|
||||
|
||||
#### ../migrate.sh
|
||||
|
||||
This file migrate every models with database in app and generate UML
|
||||
|
||||
#### ../run.sh
|
||||
|
||||
This file running application
|
||||
|
||||
## UML
|
||||
|
||||
### Class Diagram
|
||||
|
||||

|
||||
|
||||
### Class Diagram By Apps
|
||||
|
||||

|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,48 +0,0 @@
|
|||
from django.db import models
|
||||
from django.http import HttpResponse
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.auth import authenticate
|
||||
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.authtoken.models import Token
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class AbstractUser(models.Model):
|
||||
city = models.CharField(verbose_name='City', max_length=255)
|
||||
country = models.CharField(verbose_name='Country', max_length=255)
|
||||
ip = models.CharField(verbose_name='IP', max_length=15)
|
||||
|
||||
def fromDict(self, dict):
|
||||
self.__dict__.update(dict)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
||||
class Account(User, AbstractUser):
|
||||
|
||||
def register(username, email, password):
|
||||
if Account.objects.get(username = username) is None and Account.objects.get(email = email) is None:
|
||||
Account.objects.create_user(username, email, password)
|
||||
return Response(f'Account created: ')
|
||||
|
||||
def login(username, password) -> dict:
|
||||
tryLogin = authenticate(username = username, password = password)
|
||||
if tryLogin is not None:
|
||||
user = Account.objects.get(username = username)
|
||||
token = Token.objects.create(user = user)
|
||||
return token.__dict__
|
||||
else:
|
||||
return { error: 'login failed'}
|
||||
|
||||
def logout():
|
||||
pass
|
||||
|
||||
def update(self, userDict):
|
||||
self.fromDict(userDict)
|
||||
self.save
|
||||
|
||||
|
||||
class Guest(AbstractUser):
|
||||
pass
|
||||
Binary file not shown.
|
|
@ -1,26 +0,0 @@
|
|||
# Generated by Django 3.0.7 on 2020-06-17 12:26
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('account', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Album',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=255)),
|
||||
('description', models.CharField(max_length=255)),
|
||||
('image', models.TextField()),
|
||||
('url_code', models.CharField(max_length=255)),
|
||||
('user', models.ManyToManyField(to='account.Account')),
|
||||
],
|
||||
),
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,11 +0,0 @@
|
|||
from django.db import models
|
||||
from account.models import Account
|
||||
|
||||
|
||||
class Album(models.Model):
|
||||
title = models.CharField(max_length=255)
|
||||
description = models.CharField(max_length=255)
|
||||
image = models.TextField()
|
||||
url_code = models.CharField(max_length=255)
|
||||
user = models.ManyToManyField(Account)
|
||||
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,3 +0,0 @@
|
|||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
python manage.py makemigrations
|
||||
python manage.py migrate
|
||||
python manage.py graph_models -a -g -o class_diagram_by_apps.png
|
||||
python manage.py graph_models -a -o class_diagram.png
|
||||
|
||||
# directory structure
|
||||
# tree -I '.git|__pycache__|migrations|__init__.py'
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
# Generated by Django 3.0.8 on 2020-07-06 15:59
|
||||
|
||||
from django.conf import settings
|
||||
import django.contrib.auth.models
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('auth', '0011_update_proxy_permissions'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Account',
|
||||
fields=[
|
||||
('user_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL)),
|
||||
('city', models.CharField(max_length=255, verbose_name='City')),
|
||||
('country', models.CharField(max_length=255, verbose_name='Country')),
|
||||
('ip', models.CharField(max_length=15, verbose_name='IP')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'user',
|
||||
'verbose_name_plural': 'users',
|
||||
'abstract': False,
|
||||
},
|
||||
bases=('auth.user', models.Model),
|
||||
managers=[
|
||||
('objects', django.contrib.auth.models.UserManager()),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Album',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=255)),
|
||||
('description', models.CharField(max_length=255)),
|
||||
('image', models.TextField()),
|
||||
('url_code', models.CharField(max_length=255)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='portfolio.Account')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Guest',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('city', models.CharField(max_length=255, verbose_name='City')),
|
||||
('country', models.CharField(max_length=255, verbose_name='Country')),
|
||||
('ip', models.CharField(max_length=15, verbose_name='IP')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Track',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=255)),
|
||||
('description', models.CharField(max_length=1000)),
|
||||
('text', models.TextField()),
|
||||
('image', models.TextField()),
|
||||
('audio', models.TextField()),
|
||||
('url_code', models.CharField(max_length=255)),
|
||||
('album', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='portfolio.Album')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='portfolio.Account')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UserComment',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('text', models.CharField(max_length=255)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='portfolio.Account')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='TrackRow',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('row_number', models.IntegerField()),
|
||||
('group', models.BooleanField()),
|
||||
('leader', models.BooleanField()),
|
||||
('link', models.IntegerField(default=None)),
|
||||
('text', models.TextField(default=None)),
|
||||
('description', models.TextField(default=None)),
|
||||
('image', models.TextField(default=None)),
|
||||
('track', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='portfolio.Track')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='TrackRating',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('value', models.PositiveSmallIntegerField(choices=[(1, 'POSITIVE'), (0, 'NEGATIVE')], verbose_name='Type of rating (1 - POSITIVE, 0 - NEGATIVE)')),
|
||||
('track', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='portfolio.Track')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='portfolio.Account')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='GuestComment',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('text', models.CharField(max_length=255)),
|
||||
('guest', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='portfolio.Guest')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='CommentRating',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('value', models.PositiveSmallIntegerField(choices=[(1, 'POSITIVE'), (0, 'NEGATIVE')], verbose_name='Type of rating (1 - POSITIVE, 0 - NEGATIVE)')),
|
||||
('comment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='portfolio.UserComment')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='portfolio.Account')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='AlbumRating',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('value', models.PositiveSmallIntegerField(choices=[(1, 'POSITIVE'), (0, 'NEGATIVE')], verbose_name='Type of rating (1 - POSITIVE, 0 - NEGATIVE)')),
|
||||
('album', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='portfolio.Album')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='portfolio.Account')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
# Generated by Django 3.0.8 on 2020-07-24 10:12
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('portfolio', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameModel(
|
||||
old_name='CommentRating',
|
||||
new_name='GuestCommentRating',
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='guestcommentrating',
|
||||
name='comment',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='portfolio.GuestComment'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UserCommentRating',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('value', models.PositiveSmallIntegerField(choices=[(1, 'POSITIVE'), (0, 'NEGATIVE')], verbose_name='Type of rating (1 - POSITIVE, 0 - NEGATIVE)')),
|
||||
('comment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='portfolio.UserComment')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='portfolio.Account')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,7 +1,16 @@
|
|||
pip install django
|
||||
|
||||
pip install django-cors-headers
|
||||
pip install djangorestframework
|
||||
pip install django-filter
|
||||
pip install django-rest-swagger
|
||||
pip install django-enumfield
|
||||
pip install django-rest-enumfield
|
||||
pip install drf_yasg
|
||||
|
||||
pip install pyjwt
|
||||
pip install markdown
|
||||
|
||||
pip install django_extensions
|
||||
pip install pydotplus
|
||||
|
||||
# for runing generate UML:
|
||||
# apt-get install graphviz
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,3 +0,0 @@
|
|||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,4 +1,4 @@
|
|||
# Generated by Django 3.0.7 on 2020-06-17 12:26
|
||||
# Generated by Django 3.0.8 on 2020-07-24 10:21
|
||||
|
||||
from django.conf import settings
|
||||
import django.contrib.auth.models
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,61 @@
|
|||
from django.db import models
|
||||
from django.http import HttpResponse
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from rest_framework.response import Response
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class AbstractUser(models.Model):
|
||||
city = models.CharField(verbose_name='City', max_length=255)
|
||||
country = models.CharField(verbose_name='Country', max_length=255)
|
||||
ip = models.CharField(verbose_name='IP', max_length=15)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
||||
class Account(User, AbstractUser):
|
||||
|
||||
def fromDict(self, dict):
|
||||
self.__dict__.update(dict)
|
||||
|
||||
def toDict(self) -> dict:
|
||||
return {
|
||||
'id': self.id,
|
||||
'username': self.username,
|
||||
'password': None,
|
||||
'email': self.email,
|
||||
'ip': self.ip,
|
||||
'city': self.city,
|
||||
'country': self.country
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def register(userDict) -> dict:
|
||||
account = Account.objects.create_user(
|
||||
userDict['username'],
|
||||
userDict['email'],
|
||||
userDict['password'],
|
||||
)
|
||||
account.ip = userDict['ip']
|
||||
account.city = userDict['city'],
|
||||
account.country = userDict['country']
|
||||
account.save()
|
||||
return account.toDict()
|
||||
|
||||
def update(self, userDict) -> dict:
|
||||
if 'password' in userDict:
|
||||
password = userDict.pop('password')
|
||||
self.set_password(password)
|
||||
self.fromDict(userDict)
|
||||
self.save()
|
||||
return self.toDict()
|
||||
|
||||
def set_password(self, raw_password):
|
||||
return super().set_password(raw_password)
|
||||
|
||||
|
||||
class Guest(AbstractUser):
|
||||
pass
|
||||
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
from .models import Account, Guest
|
||||
|
||||
from rest_framework import serializers
|
||||
from rest_framework.authtoken.models import Token
|
||||
|
||||
from django.contrib.auth import authenticate, logout as logoutDjango
|
||||
from django.core.paginator import Paginator
|
||||
from django.http import JsonResponse
|
||||
|
||||
|
||||
class AccountGetSerializer(serializers.ModelSerializer):
|
||||
id = serializers.IntegerField(read_only = True)
|
||||
username = serializers.CharField(max_length = 100)
|
||||
email = serializers.EmailField()
|
||||
ip = serializers.CharField(max_length = 12)
|
||||
city = serializers.CharField(max_length = 255)
|
||||
country = serializers.CharField(max_length = 255)
|
||||
|
||||
class Meta:
|
||||
model = Account
|
||||
fields = ['id', 'username', 'email', 'ip', 'city', 'country']
|
||||
|
||||
|
||||
class AccountSerializer(AccountGetSerializer):
|
||||
password = serializers.CharField(max_length = 100)
|
||||
|
||||
def create(self, validated_data):
|
||||
return Account.register(validated_data)
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
return instance.update(validated_data)
|
||||
|
||||
class Meta:
|
||||
model = Account
|
||||
fields = ['id', 'username', 'password', 'email', 'ip', 'city', 'country']
|
||||
|
||||
class AccountAuthSerializer(serializers.ModelSerializer):
|
||||
username = serializers.CharField(max_length = 100)
|
||||
password = serializers.CharField(max_length = 100)
|
||||
|
||||
@staticmethod
|
||||
def login(username, password) -> dict:
|
||||
tryLogin = authenticate(username = username, password = password)
|
||||
if tryLogin is not None:
|
||||
user = Account.objects.get(username = username)
|
||||
try:
|
||||
token = Token.objects.get(user = user)
|
||||
except:
|
||||
token = Token.objects.create(user = user)
|
||||
return { 'Authorization': 'Token ' + token.key, 'user': user.toDict() }
|
||||
else:
|
||||
return { 'error': 'login failed'}
|
||||
|
||||
@staticmethod
|
||||
def logout(request, format=None):
|
||||
logoutDjango(request)
|
||||
tokenStr = request.headers['Authorization'].split(' ')[1]
|
||||
token = Token.objects.get(key = tokenStr)
|
||||
token.delete()
|
||||
return { 'info': 'logout success' }
|
||||
|
||||
class Meta:
|
||||
model = Account
|
||||
fields = ['username', 'password']
|
||||
|
||||
|
||||
class GuestSerializer(serializers.HyperlinkedModelSerializer):
|
||||
id = serializers.IntegerField(read_only = True)
|
||||
ip = serializers.CharField(max_length = 12)
|
||||
city = serializers.CharField(max_length = 255)
|
||||
country = serializers.CharField(max_length = 255)
|
||||
|
||||
class Meta:
|
||||
model = Guest
|
||||
fields = ['id', 'ip', 'city', 'country']
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
from rest_framework import viewsets, mixins
|
||||
from rest_framework.response import Response
|
||||
from rest_framework import permissions
|
||||
from rest_framework.authtoken.views import ObtainAuthToken
|
||||
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
|
||||
from django.shortcuts import get_object_or_404
|
||||
|
||||
from .models import Account, Guest
|
||||
from .serializers import *
|
||||
|
||||
|
||||
class AnonAndUserPermissions(permissions.BasePermission):
|
||||
"""
|
||||
Anonymous user always can create && User can modify self records only
|
||||
|
||||
this is override of permissions in settings
|
||||
"""
|
||||
def has_object_permission(self, request, view, obj):
|
||||
if request.method == 'POST':
|
||||
return True
|
||||
return str(obj.username) == str(request.user)
|
||||
|
||||
|
||||
class AccountViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
A User CRUD (abstract from `viewsets.ModelViewSet`):
|
||||
`GET`: `list()`
|
||||
`GET`: `retrieve()` /parameter {id}
|
||||
`POST`: `create()`
|
||||
`PUT`&`PATCH`: `update()` /parameter {id}
|
||||
`DELETE`: `destroy()` /parameter {id}
|
||||
"""
|
||||
queryset = Account.objects.all()
|
||||
serializer_class = AccountSerializer
|
||||
permission_classes = (AnonAndUserPermissions, )
|
||||
|
||||
@swagger_auto_schema(responses={ 200: AccountGetSerializer })
|
||||
def retrieve(self, request, pk=None):
|
||||
print(pk)
|
||||
account = get_object_or_404(self.queryset, pk=pk)
|
||||
serializer = AccountGetSerializer(account)
|
||||
return Response(serializer.data)
|
||||
|
||||
@swagger_auto_schema(responses={ 200: AccountGetSerializer })
|
||||
def list(self, request, *args, **kwargs):
|
||||
serializer = AccountGetSerializer(self.queryset, many=True)
|
||||
return Response(serializer.data)
|
||||
|
||||
|
||||
class AccountAuth(ObtainAuthToken):
|
||||
"""
|
||||
A User Authorization (abstract from ObtainAuthToken):
|
||||
`POST`: `login()` /create auth token
|
||||
`DELETE`: `logout()` /get auth token from header
|
||||
"""
|
||||
queryset = Account.objects.all()
|
||||
serializer_class = AccountAuthSerializer
|
||||
|
||||
@swagger_auto_schema(
|
||||
responses={ 200: '{ Token: "Token", user: { AccountGet } }' },
|
||||
request_body=AccountAuthSerializer
|
||||
)
|
||||
def post(self, request, *args, **kwargs):
|
||||
serializer = self.serializer_class(data=request.data, context={'request': request})
|
||||
serializer.is_valid(raise_exception=True)
|
||||
username = serializer.validated_data['username']
|
||||
password = serializer.validated_data['password']
|
||||
return Response(AccountAuthSerializer.login(username, password))
|
||||
|
||||
@swagger_auto_schema(responses={ 200: '{ info: logout }' })
|
||||
def delete(self, request, *args, **kwargs):
|
||||
return Response(self.serializer_class.logout(request))
|
||||
|
||||
|
||||
class GuestViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
A Guest CRUD (abstract from `viewsets.ModelViewSet`):
|
||||
`GET`: `list()`
|
||||
`GET`: `retrieve()` /parameter {id}
|
||||
`POST`: `create()`
|
||||
`PUT`&`PATCH`: `update()` /parameter {id}
|
||||
`DELETE`: `destroy()` /parameter {id}
|
||||
"""
|
||||
queryset = Guest.objects.all()
|
||||
serializer_class = GuestSerializer
|
||||
permission_classes = (AnonAndUserPermissions, )
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,64 @@
|
|||
# Generated by Django 3.0.8 on 2020-07-24 10:21
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('account', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Album',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=255)),
|
||||
('description', models.CharField(max_length=255)),
|
||||
('image', models.TextField()),
|
||||
('url_code', models.CharField(max_length=255)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='account.Account')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Track',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=255)),
|
||||
('description', models.CharField(max_length=1000)),
|
||||
('text', models.TextField()),
|
||||
('image', models.TextField()),
|
||||
('audio', models.TextField()),
|
||||
('url_code', models.CharField(max_length=255)),
|
||||
('album', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='album.Album')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='account.Account')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='TrackRow',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('row_number', models.IntegerField()),
|
||||
('group', models.BooleanField()),
|
||||
('leader', models.BooleanField()),
|
||||
('link', models.IntegerField(default=None)),
|
||||
('text', models.TextField(default=None)),
|
||||
('description', models.TextField(default=None)),
|
||||
('image', models.TextField(default=None)),
|
||||
('track', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='album.Track')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,58 @@
|
|||
from django.db import models
|
||||
|
||||
from portfolio.account.models import Account
|
||||
from portfolio.utils import OneToManyModel
|
||||
|
||||
class Album(OneToManyModel):
|
||||
title = models.CharField(max_length=255)
|
||||
description = models.CharField(max_length=255)
|
||||
image = models.TextField()
|
||||
url_code = models.CharField(max_length=255)
|
||||
user = models.ForeignKey(Account, on_delete=models.DO_NOTHING)
|
||||
|
||||
|
||||
class Track(OneToManyModel):
|
||||
title = models.CharField(max_length=255)
|
||||
description = models.CharField(max_length=1000)
|
||||
text = models.TextField()
|
||||
image = models.TextField()
|
||||
audio = models.TextField()
|
||||
url_code = models.CharField(max_length=255)
|
||||
album = models.ForeignKey(Album, on_delete=models.CASCADE)
|
||||
user = models.ForeignKey(Account, on_delete=models.CASCADE)
|
||||
|
||||
|
||||
class TrackRow(OneToManyModel):
|
||||
row_number = models.IntegerField()
|
||||
group = models.BooleanField()
|
||||
leader = models.BooleanField()
|
||||
link = models.IntegerField(default=None)
|
||||
text = models.TextField(default=None)
|
||||
description = models.TextField(default=None)
|
||||
image = models.TextField(default=None)
|
||||
track = models.ForeignKey(Track, on_delete=models.CASCADE)
|
||||
|
||||
def toDict(self):
|
||||
if self.link is not None:
|
||||
return {
|
||||
self.row_number: {
|
||||
'group': self.gruop,
|
||||
'leader': self.leader,
|
||||
'link': self.link,
|
||||
'text': self.text,
|
||||
'description': None,
|
||||
'image': None
|
||||
}
|
||||
}
|
||||
else:
|
||||
return {
|
||||
self.row_number: {
|
||||
'group': self.gruop,
|
||||
'leader': self.leader,
|
||||
'link': None,
|
||||
'text': None,
|
||||
'description': self.description,
|
||||
'image': self.image
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from rest_framework.reverse import reverse
|
||||
|
||||
from .models import *
|
||||
|
||||
|
||||
class TrackRowSerializer(serializers.ModelSerializer):
|
||||
id = serializers.IntegerField(read_only = True)
|
||||
track_id = serializers.IntegerField()
|
||||
row_number = serializers.IntegerField()
|
||||
group = serializers.BooleanField()
|
||||
leader = serializers.BooleanField()
|
||||
link = serializers.IntegerField()
|
||||
text = serializers.CharField()
|
||||
description = serializers.CharField()
|
||||
image = serializers.CharField()
|
||||
|
||||
def create(self, validated_data):
|
||||
return TrackRow.create(TrackRow, validated_data)
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
return instance.update(validated_data)
|
||||
|
||||
class Meta:
|
||||
model = TrackRow
|
||||
fields = ['id', 'track_id','row_number', 'group', 'leader', 'link', 'text', 'description', 'image']
|
||||
|
||||
|
||||
class TrackSerializer(serializers.ModelSerializer):
|
||||
id = serializers.IntegerField(read_only = True)
|
||||
album_id = serializers.IntegerField()
|
||||
user_id = serializers.IntegerField()
|
||||
title = serializers.CharField(max_length=255)
|
||||
description = serializers.CharField(max_length=1000)
|
||||
text = serializers.CharField()
|
||||
image = serializers.CharField()
|
||||
audio = serializers.CharField()
|
||||
url_code = serializers.CharField(max_length=255)
|
||||
track_rows = TrackRowSerializer(many=True, read_only=True)
|
||||
|
||||
def create(self, validated_data):
|
||||
return Track.create(Track, validated_data)
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
return instance.update(validated_data)
|
||||
|
||||
# track_rows = serializers.SlugRelatedField(
|
||||
# many=True,
|
||||
# read_only=True,
|
||||
# slug_field='row_number'
|
||||
# )
|
||||
|
||||
# view_name = 'track'
|
||||
# queryset = Track.objects.all()
|
||||
|
||||
# def get_url(self, obj, view_name, request, format):
|
||||
# url_kargs = {
|
||||
# 'album_id': obj.album.id,
|
||||
# 'id': obj.id
|
||||
# }
|
||||
# return reverse(view_name, kwargs=url_kargs, request=request, format=format)
|
||||
|
||||
# def get_object(self, view_name, view_args, view_kwargs):
|
||||
# lookup_kwargs = {
|
||||
# 'album_id': view_kwargs['album_id'],
|
||||
# 'id': view_kwargs['id']
|
||||
# }
|
||||
# return self.get_queryset().get(**lookup_kwargs)
|
||||
|
||||
|
||||
class Meta:
|
||||
model = Track
|
||||
fields = ['id', 'album_id', 'user_id', 'title', 'description', 'text', 'image', 'audio', 'url_code', 'track_rows']
|
||||
|
||||
|
||||
class AlbumSerializer(serializers.ModelSerializer):
|
||||
id = serializers.IntegerField(read_only = True)
|
||||
user_id = serializers.IntegerField()
|
||||
title = serializers.CharField(max_length=255)
|
||||
description = serializers.CharField(max_length=255)
|
||||
image = serializers.CharField()
|
||||
url_code = serializers.CharField(max_length=255)
|
||||
tracks = TrackSerializer(many=True, read_only=True)
|
||||
|
||||
def create(self, validated_data):
|
||||
return Album.create(Album, validated_data)
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
return Album.update(validated_data)
|
||||
|
||||
class Meta:
|
||||
model = Album
|
||||
fields = ['id', 'user_id', 'title', 'description', 'image', 'url_code', 'tracks']
|
||||
|
||||
|
||||
|
||||
# Relations
|
||||
|
||||
|
||||
# class TrackTrackRowRelation(serializers.RelatedField):
|
||||
# def to_representation(self, value):
|
||||
# serializer = TrackSerializer(value.get_queryset()[0])
|
||||
# return serializer.data
|
||||
|
||||
|
||||
# class AlbumTrackRelation(serializers.RelatedField):
|
||||
# def to_representation(self, value):
|
||||
# serializer = AlbumSerializer(value.get_queryset()[0])
|
||||
# return serializer.data
|
||||
|
||||
|
||||
# class TrackRowSerializerFull(TrackRowSerializer):
|
||||
# """
|
||||
# TrackRow + Track id
|
||||
# """
|
||||
# track_id = TrackTrackRowRelation(queryset=Track.objects.all())
|
||||
|
||||
# class Meta:
|
||||
# model = TrackRow
|
||||
# fields = ['id', 'track_id', 'row_number', 'group', 'leader', 'link', 'text', 'description', 'image']
|
||||
|
||||
|
||||
# class TrackSerializerFull(TrackSerializer):
|
||||
# """
|
||||
# Track + Album id
|
||||
# """
|
||||
# album_id = AlbumTrackRelation(queryset=Album.objects.all())
|
||||
|
||||
# def create(self, validated_data):
|
||||
# return super().create(validated_data)
|
||||
|
||||
# class Meta:
|
||||
# model = Track
|
||||
# fields = ['id', 'album_id', 'title', 'description', 'text', 'image', 'audio', 'url_code', 'track_rows']
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
from django.shortcuts import render
|
||||
|
||||
from rest_framework import viewsets
|
||||
|
||||
from .models import *
|
||||
from .serializers import *
|
||||
|
||||
|
||||
class TrackViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
A Tack CRUD (abstract from `viewsets.ModelViewSet`):
|
||||
`GET`: `list()`
|
||||
`GET`: `retrieve()` /parameter {id}
|
||||
`POST`: `create()`
|
||||
`PUT`&`PATCH`: `update()` /parameter {id}
|
||||
`DELETE`: `destroy()` /parameter {id}
|
||||
"""
|
||||
queryset = Track.objects.all()
|
||||
serializer_class = TrackSerializer
|
||||
|
||||
|
||||
class TrackRowViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
A TrackRow CRUD (abstract from `viewsets.ModelViewSet`):
|
||||
`GET`: `list()`
|
||||
`GET`: `retrieve()` /parameter {id}
|
||||
`POST`: `create()`
|
||||
`PUT`&`PATCH`: `update()` /parameter {id}
|
||||
`DELETE`: `destroy()` /parameter {id}
|
||||
"""
|
||||
queryset = TrackRow.objects.all()
|
||||
serializer_class = TrackRowSerializer
|
||||
|
||||
|
||||
class AlbumViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
A Album CRUD (abstract from `viewsets.ModelViewSet`):
|
||||
`GET`: `list()`
|
||||
`GET`: `retrieve()` /parameter {id}
|
||||
`POST`: `create()`
|
||||
`PUT`&`PATCH`: `update()` /parameter {id}
|
||||
`DELETE`: `destroy()` /parameter {id}
|
||||
"""
|
||||
queryset = Album.objects.all()
|
||||
serializer_class = AlbumSerializer
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,4 +1,4 @@
|
|||
# Generated by Django 3.0.7 on 2020-06-17 12:26
|
||||
# Generated by Django 3.0.8 on 2020-07-24 10:21
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,10 +1,12 @@
|
|||
from django.db import models
|
||||
|
||||
from account.models import Account, Guest
|
||||
from portfolio.account.models import Account, Guest
|
||||
from portfolio.album.models import Track
|
||||
|
||||
|
||||
class AbstractComment(models.Model):
|
||||
text = models.CharField(max_length=255)
|
||||
track = models.ForeignKey(Track, on_delete=models.CASCADE)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from .models import UserComment, GuestComment
|
||||
|
||||
class UserCommentSerializer(serializers.ModelSerializer):
|
||||
id = serializers.IntegerField(read_only=True)
|
||||
user_id = serializers.IntegerField()
|
||||
text = serializers.CharField()
|
||||
|
||||
class Meta:
|
||||
model = UserComment
|
||||
fields = [ 'id', 'user_id', 'text']
|
||||
|
||||
class GuestCommentSerializer(serializers.ModelSerializer):
|
||||
id = serializers.IntegerField(read_only=True)
|
||||
guest_id = serializers.IntegerField()
|
||||
text = serializers.CharField()
|
||||
|
||||
class Meta:
|
||||
model = GuestComment
|
||||
fields = [ 'id', 'guest_id', 'text']
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
from django.shortcuts import render
|
||||
|
||||
from rest_framework import viewsets, mixins
|
||||
from rest_framework import permissions
|
||||
|
||||
from .models import UserComment, GuestComment
|
||||
from .serializers import UserCommentSerializer, GuestCommentSerializer
|
||||
|
||||
|
||||
class AnonAndUserPermissions(permissions.BasePermission):
|
||||
"""
|
||||
Anonymous user always can create && User can modify self records only
|
||||
|
||||
this is override of permissions in settings
|
||||
"""
|
||||
def has_object_permission(self, request, view, obj):
|
||||
if request.method == 'POST':
|
||||
return True
|
||||
return "AnonymousUser" != str(request.user)
|
||||
|
||||
|
||||
class UserCommentViewSet(
|
||||
mixins.ListModelMixin,
|
||||
mixins.CreateModelMixin,
|
||||
mixins.DestroyModelMixin,
|
||||
viewsets.GenericViewSet
|
||||
):
|
||||
|
||||
queryset = UserComment.objects.all()
|
||||
serializer_class = UserCommentSerializer
|
||||
|
||||
|
||||
class GuestCommentViewSet(
|
||||
mixins.ListModelMixin,
|
||||
mixins.CreateModelMixin,
|
||||
mixins.DestroyModelMixin,
|
||||
viewsets.GenericViewSet
|
||||
):
|
||||
|
||||
queryset = GuestComment.objects.all()
|
||||
serializer_class = GuestCommentSerializer
|
||||
permission_classes = (AnonAndUserPermissions, )
|
||||
Binary file not shown.
|
|
@ -1,4 +1,4 @@
|
|||
# Generated by Django 3.0.7 on 2020-06-17 12:26
|
||||
# Generated by Django 3.0.8 on 2020-07-24 10:21
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
|
@ -8,7 +8,7 @@ class Migration(migrations.Migration):
|
|||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('song', '0001_initial'),
|
||||
('album', '0001_initial'),
|
||||
('account', '0001_initial'),
|
||||
]
|
||||
|
||||
|
|
@ -18,7 +18,7 @@ class Migration(migrations.Migration):
|
|||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=255)),
|
||||
('song', models.ManyToManyField(to='song.Song')),
|
||||
('track', models.ManyToManyField(to='album.Track')),
|
||||
('user', models.ManyToManyField(to='account.Account')),
|
||||
],
|
||||
),
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,11 +1,11 @@
|
|||
from django.db import models
|
||||
|
||||
from song.models import Song
|
||||
from account.models import Account
|
||||
from portfolio.album.models import Track
|
||||
from portfolio.account.models import Account
|
||||
|
||||
|
||||
class Playlist(models.Model):
|
||||
title = models.CharField(max_length=255)
|
||||
user = models.ManyToManyField(Account)
|
||||
song = models.ManyToManyField(Song)
|
||||
track = models.ManyToManyField(Track)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue