Compare commits

...

26 Commits

Author SHA1 Message Date
Kamil aa1e0912d2
Update README.md 2020-09-15 16:51:51 +02:00
Kamil f0b5429070
Update README.md 2020-09-15 16:50:30 +02:00
Kamil 1a5582b625
Update README.md 2020-09-15 16:50:09 +02:00
TBS093A 1cb80a8322 add CSRF and CORS settings 2020-07-25 00:35:56 +02:00
TBS093A 6e61d83bbc modify comments models && upgrade README.md 2020-07-24 14:29:22 +02:00
TBS093A de22f24267 upgrade README.md 2020-07-24 14:06:55 +02:00
TBS093A 4a6123edf0 upgrade README.md 2020-07-24 14:06:11 +02:00
TBS093A c4419bd483 upgrade README.md 2020-07-24 14:03:52 +02:00
TBS093A 9afcd67eb3 upgrade README.md 2020-07-24 14:02:03 +02:00
TBS093A 7ef2e263a2 upgrade README.md 2020-07-24 14:01:03 +02:00
TBS093A 85bb627391 upgrade README.md 2020-07-24 13:43:10 +02:00
TBS093A 8c1a3d9843 upgrade migrate.sh && add README.md with UML 2020-07-24 13:40:16 +02:00
TBS093A e221d223ac pycache update && modify migrate shell && add readme.md with uml 2020-07-24 13:38:12 +02:00
TBS093A a9c1bf739f change packages && mv all apps to portfolio package 2020-07-24 13:17:01 +02:00
TBS093A fbd62622ee mv all apps to default directory 2020-07-24 12:24:33 +02:00
TBS093A e2c5274c53 create GuestCommentRating Model 2020-07-24 12:14:26 +02:00
TBS093A 9da2611fbb upgrade comments && add UML generator && modified shell files && fix urls 2020-07-24 11:15:06 +02:00
TBS093A 1d07048913 upgrade ratings list 2020-07-06 18:07:23 +02:00
TBS093A 89fc4b3099 create ratings endpoints // enumField problem #TODO 2020-07-03 22:04:10 +02:00
TBS093A 709df5fb90 upgrade documentation -> Account app 2020-06-21 12:16:36 +02:00
TBS093A 6a54b4d959 upgrade permissions for Account/Guest classes && add documentation for views in Account 2020-06-21 11:55:18 +02:00
TBS093A 344f71295c merge endpoints Track/TrackRow to Album && create full crud -> Album && clear database 2020-06-21 00:55:39 +02:00
TBS093A 1c84adcbda upgrade authorization && fix permission bugs 2020-06-20 19:41:41 +02:00
TBS093A 88b75e1e9c add full authorization 2020-06-20 17:16:55 +02:00
TBS093A 08f29d5cc6 complete account serializer && upgrade song models 2020-06-20 12:03:30 +02:00
TBS093A 0b25a73127 create others schemas in one endpoint -> users 2020-06-19 12:32:04 +02:00
138 changed files with 1279 additions and 236 deletions

3
.gitignore vendored 100644 → 100755
View File

@ -1,3 +1,4 @@
# database
*.sqlite3
*.sqlite3
*.png

76
README.md 100644
View File

@ -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](https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/12abb353-ab91-4433-96d3-b5d9c5847254/de1x3ts-af1f9daf-1aad-439a-87e4-891ea7934b90.png/v1/fill/w_1280,h_1199,strp/music_service_class_diagram_by_00x097_de1x3ts-fullview.png?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOiIsImlzcyI6InVybjphcHA6Iiwib2JqIjpbW3siaGVpZ2h0IjoiPD0xMTk5IiwicGF0aCI6IlwvZlwvMTJhYmIzNTMtYWI5MS00NDMzLTk2ZDMtYjVkOWM1ODQ3MjU0XC9kZTF4M3RzLWFmMWY5ZGFmLTFhYWQtNDM5YS04N2U0LTg5MWVhNzkzNGI5MC5wbmciLCJ3aWR0aCI6Ijw9MTI4MCJ9XV0sImF1ZCI6WyJ1cm46c2VydmljZTppbWFnZS5vcGVyYXRpb25zIl19.MQ8Y8G1kYVZE4WzlAbs_iAx_8fztG-uhhTMvzVO6Ovw)
### Class Diagram By Apps
![class_diagram_by_apps](https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/12abb353-ab91-4433-96d3-b5d9c5847254/de1x3sf-d977ce0b-fca5-498c-84ce-f899375491ba.png/v1/fill/w_1280,h_811,q_80,strp/music_service_class_diagram_by_apps_by_00x097_de1x3sf-fullview.jpg?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOiIsImlzcyI6InVybjphcHA6Iiwib2JqIjpbW3siaGVpZ2h0IjoiPD04MTEiLCJwYXRoIjoiXC9mXC8xMmFiYjM1My1hYjkxLTQ0MzMtOTZkMy1iNWQ5YzU4NDcyNTRcL2RlMXgzc2YtZDk3N2NlMGItZmNhNS00OThjLTg0Y2UtZjg5OTM3NTQ5MWJhLnBuZyIsIndpZHRoIjoiPD0xMjgwIn1dXSwiYXVkIjpbInVybjpzZXJ2aWNlOmltYWdlLm9wZXJhdGlvbnMiXX0.sJmLVbWBIkyd846m3I6vfYhQpdJiOzfe1KOSUKQBP9c)

Binary file not shown.

View File

@ -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

View File

@ -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')),
],
),
]

View File

@ -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)

View File

@ -1,3 +0,0 @@
from django.shortcuts import render
# Create your views here.

View File

@ -1,3 +0,0 @@
from django.shortcuts import render
# Create your views here.

7
migrate.sh 100755
View File

@ -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'

View File

@ -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,
},
),
]

View File

@ -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,
},
),
]

View File

Binary file not shown.

13
packages.sh 100644 → 100755
View File

@ -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

View File

@ -1,3 +0,0 @@
from django.shortcuts import render
# Create your views here.

0
portfolio/__init__.py 100644 → 100755
View File

View File

Binary file not shown.

View File

View File

View File

View File

@ -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

View File

@ -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

View File

@ -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']

View File

View File

@ -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, )

View File

View File

View File

@ -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,
},
),
]

View File

@ -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
}
}

View File

@ -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']

View File

View File

@ -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

0
portfolio/asgi.py 100644 → 100755
View File

View File

View File

View File

@ -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

View File

@ -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

View File

@ -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']

View File

View File

@ -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, )

View File

View File

View File

@ -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')),
],
),

View File

@ -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)

View File

View File

Some files were not shown because too many files have changed in this diff Show More