9
lists/forms.py
Normal file
9
lists/forms.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
from django import forms
|
||||||
|
|
||||||
|
from lists.models import ListItem
|
||||||
|
|
||||||
|
|
||||||
|
class ListItemForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = ListItem
|
||||||
|
fields = ['entity', 'tags']
|
||||||
76
lists/migrations/0001_initial.py
Normal file
76
lists/migrations/0001_initial.py
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
# Generated by Django 3.0.7 on 2020-06-28 22:41
|
||||||
|
|
||||||
|
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='Entity',
|
||||||
|
fields=[
|
||||||
|
('mbid', models.CharField(max_length=36, primary_key=True, serialize=False)),
|
||||||
|
('entity_type', models.CharField(choices=[('artist', 'Artista'), ('release-group', 'Grupo de Lanzamientos'), ('release', 'Lanzamiento'), ('recording', 'Grabación')], max_length=25)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ListItem',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('entity', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='lists.Entity')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Opinion',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('opinion_text', models.TextField()),
|
||||||
|
('entity', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='lists.ListItem')),
|
||||||
|
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Tag',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=50)),
|
||||||
|
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Stars',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('quantity', models.IntegerField()),
|
||||||
|
('entity', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='lists.ListItem')),
|
||||||
|
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='OpinionHelpful',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('vote', models.CharField(choices=[('Y', 'Si'), ('N', 'No'), ('F', 'Divertida')], max_length=1)),
|
||||||
|
('opinion', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='lists.Opinion')),
|
||||||
|
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='listitem',
|
||||||
|
name='tags',
|
||||||
|
field=models.ManyToManyField(to='lists.Tag'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='listitem',
|
||||||
|
name='user',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='list', to=settings.AUTH_USER_MODEL),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -23,15 +23,15 @@ class Entity(Model):
|
|||||||
|
|
||||||
class Tag(Model):
|
class Tag(Model):
|
||||||
"""Tag creada por un usuario"""
|
"""Tag creada por un usuario"""
|
||||||
user = ForeignKey(User, on_delete=CASCADE)
|
user = ForeignKey(User, on_delete=CASCADE, related_name='tags')
|
||||||
name = CharField(max_length=50)
|
name = CharField(max_length=50)
|
||||||
|
|
||||||
|
|
||||||
class ListItem(Model):
|
class ListItem(Model):
|
||||||
"""Item de la lista de un usuario"""
|
"""Item de la lista de un usuario"""
|
||||||
user = ForeignKey(User, on_delete=CASCADE)
|
user = ForeignKey(User, on_delete=CASCADE, related_name='list')
|
||||||
entity = ForeignKey(Entity, on_delete=CASCADE)
|
entity = ForeignKey(Entity, on_delete=CASCADE)
|
||||||
tags = ManyToManyField(Tag, on_delete=CASCADE)
|
tags = ManyToManyField(Tag)
|
||||||
|
|
||||||
|
|
||||||
class Stars(Model):
|
class Stars(Model):
|
||||||
|
|||||||
138
lists/test.py
Normal file
138
lists/test.py
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
import json
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
from django.test import TestCase
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
|
from lists.models import ListItem, Entity, Tag
|
||||||
|
from users.models import User
|
||||||
|
|
||||||
|
|
||||||
|
class TestList(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.user = User.objects.create_user(username='user', email='email@email.com', password='superpassword')
|
||||||
|
self.other = User.objects.create_user(username='other', email='email@email.com', password='superpassword')
|
||||||
|
|
||||||
|
self.entities = [
|
||||||
|
Entity.objects.create(mbid='a', entity_type='artist'),
|
||||||
|
Entity.objects.create(mbid='b', entity_type='release-group'),
|
||||||
|
Entity.objects.create(mbid='c', entity_type='recording'),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.tags = [
|
||||||
|
Tag.objects.create(user=self.user, name='1'),
|
||||||
|
Tag.objects.create(user=self.user, name='2'),
|
||||||
|
Tag.objects.create(user=self.user, name='3')
|
||||||
|
]
|
||||||
|
|
||||||
|
for tag in self.tags:
|
||||||
|
self.user.tags.add(tag)
|
||||||
|
|
||||||
|
list_item = ListItem.objects.create(user_id=self.user.id, entity=self.entities[0])
|
||||||
|
list_item.tags.set(self.tags)
|
||||||
|
self.user.list.add(list_item)
|
||||||
|
|
||||||
|
tomorrow = timezone.now() + timedelta(1)
|
||||||
|
self.user_token = self.user.oauth2_provider_accesstoken.create(expires=tomorrow, token='usertoken')
|
||||||
|
self.other_token = self.other.oauth2_provider_accesstoken.create(expires=tomorrow, token='ohnotoken')
|
||||||
|
|
||||||
|
def _user_bearer_token(self):
|
||||||
|
return f'Bearer {self.user_token.token}'
|
||||||
|
|
||||||
|
def _other_bearer_token(self):
|
||||||
|
return f'Bearer {self.other_token.token}'
|
||||||
|
|
||||||
|
def test_get_list(self):
|
||||||
|
response = self.client.get('/api/lists/list/1', follow=True)
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertTrue('list' in response.json())
|
||||||
|
|
||||||
|
for list_item in response.json()['list']:
|
||||||
|
self.assertTrue('entity' in list_item)
|
||||||
|
self.assertTrue('tags' in list_item)
|
||||||
|
|
||||||
|
def test_get_list_user_doesnt_exists(self):
|
||||||
|
response = self.client.get('/api/lists/list/3', follow=True)
|
||||||
|
self.assertEqual(response.status_code, 404)
|
||||||
|
|
||||||
|
def test_add_to_list_is_protected(self):
|
||||||
|
response = self.client.post('/api/lists/list/1/')
|
||||||
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
|
response = self.client.post('/api/lists/list/1/',
|
||||||
|
HTTP_AUTHORIZATION=self._other_bearer_token())
|
||||||
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
|
def test_add_to_list(self):
|
||||||
|
to_add = {
|
||||||
|
'entity': 'b',
|
||||||
|
'tags': ['1', '2']
|
||||||
|
}
|
||||||
|
|
||||||
|
response = self.client.post('/api/lists/list/1/', json.dumps(to_add),
|
||||||
|
content_type='application/json',
|
||||||
|
HTTP_AUTHORIZATION=self._user_bearer_token())
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
list_item = ListItem.objects.filter(pk=2)
|
||||||
|
|
||||||
|
self.assertEqual(list_item.count(), 1)
|
||||||
|
|
||||||
|
list_item = list_item[0]
|
||||||
|
|
||||||
|
self.assertEqual(list_item.user_id, self.user.id)
|
||||||
|
self.assertEqual(list_item.entity_id, to_add['entity'])
|
||||||
|
self.assertEqual(list_item.tags.count(), len(to_add['tags']))
|
||||||
|
|
||||||
|
def test_delete_list_item_is_protected(self):
|
||||||
|
response = self.client.delete('/api/lists/list/1/1/')
|
||||||
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
|
response = self.client.delete('/api/lists/list/1/1/',
|
||||||
|
HTTP_AUTHORIZATION=self._other_bearer_token())
|
||||||
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
|
def test_delete_list_item(self):
|
||||||
|
self.assertEqual(ListItem.objects.filter(pk=1).count(), 1)
|
||||||
|
|
||||||
|
response = self.client.delete('/api/lists/list/1/1/',
|
||||||
|
HTTP_AUTHORIZATION=self._user_bearer_token())
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(ListItem.objects.filter(pk=1).count(), 0)
|
||||||
|
|
||||||
|
def test_get_list_item(self):
|
||||||
|
response = self.client.get('/api/lists/list/1/1', follow=True)
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
list_item = response.json()
|
||||||
|
self.assertEqual(list_item['entity']['mbid'], 'a')
|
||||||
|
self.assertEqual(list_item['entity']['type'], 'artist')
|
||||||
|
self.assertEqual(len(list_item['tags']), 3)
|
||||||
|
|
||||||
|
def test_update_list_item_is_protected(self):
|
||||||
|
response = self.client.put('/api/lists/list/1/1/')
|
||||||
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
|
response = self.client.put('/api/lists/list/1/1/',
|
||||||
|
HTTP_AUTHORIZATION=self._other_bearer_token())
|
||||||
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
|
def test_update_list_item(self):
|
||||||
|
self.assertEqual(ListItem.objects.get(pk=1).tags.count(), 3)
|
||||||
|
|
||||||
|
to_update = {
|
||||||
|
'entity': 'a',
|
||||||
|
'tags': ['1', '2']
|
||||||
|
}
|
||||||
|
|
||||||
|
response = self.client.put('/api/lists/list/1/1/', json.dumps(to_update),
|
||||||
|
content_type='application/json',
|
||||||
|
HTTP_AUTHORIZATION=self._user_bearer_token())
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
self.assertEqual(ListItem.objects.get(pk=1).tags.count(), 2)
|
||||||
9
lists/urls.py
Normal file
9
lists/urls.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from lists import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('list/<int:user_id>/', views.list_view),
|
||||||
|
path('list/<int:user_id>/<int:list_item_id>/', views.list_item_view),
|
||||||
|
path('tag/<int:user_id>/', views.tag_view)
|
||||||
|
]
|
||||||
193
lists/views.py
Normal file
193
lists/views.py
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
import json
|
||||||
|
from json.decoder import JSONDecodeError
|
||||||
|
|
||||||
|
from django.http import JsonResponse
|
||||||
|
from oauth2_provider.decorators import protected_resource
|
||||||
|
|
||||||
|
from lists.forms import ListItemForm
|
||||||
|
from lists.models import ListItem
|
||||||
|
from users.models import User
|
||||||
|
|
||||||
|
|
||||||
|
def list_view(request, user_id):
|
||||||
|
"""
|
||||||
|
Punto de entrada de las vistas de lista de un usuario
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Tiene que existir un usuario con el id entregado.
|
||||||
|
user = User.objects.filter(pk=user_id)
|
||||||
|
if user.count() != 1:
|
||||||
|
return JsonResponse({'status': 404, 'error': f'No existe un usuario con id {user_id}'}, status=404)
|
||||||
|
user = user[0]
|
||||||
|
|
||||||
|
if request.method == 'GET':
|
||||||
|
return _get_list(request, user)
|
||||||
|
elif request.method == 'POST':
|
||||||
|
return _add_to_list(request, user)
|
||||||
|
else:
|
||||||
|
return JsonResponse({'status': 404, 'error': 'La ruta no existe'}, status=404)
|
||||||
|
|
||||||
|
|
||||||
|
def list_item_view(request, user_id, list_item_id):
|
||||||
|
"""
|
||||||
|
Punto de entrada a las vistas de item de lista de un usuario
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Tiene que existir un usuario con el id entregado.
|
||||||
|
user = User.objects.filter(pk=user_id)
|
||||||
|
if user.count() != 1:
|
||||||
|
return JsonResponse({'status': 404, 'error': f'No existe un usuario con id {user_id}'}, status=404)
|
||||||
|
user = user[0]
|
||||||
|
|
||||||
|
# Tiene que existir un item de lista de usuario con el id entregado
|
||||||
|
list_item = ListItem.objects.filter(id=list_item_id, user_id=user_id)
|
||||||
|
if list_item.count() == 0:
|
||||||
|
return JsonResponse({'status': 404, 'error': 'No existe el list_item'}, status=404)
|
||||||
|
list_item = list_item[0]
|
||||||
|
|
||||||
|
if request.method == 'GET':
|
||||||
|
return _get_list_item(request, user, list_item)
|
||||||
|
if request.method == 'PUT':
|
||||||
|
return _update_list_item(request, user, list_item)
|
||||||
|
elif request.method == 'DELETE':
|
||||||
|
return _remove_list_item(request, user, list_item)
|
||||||
|
else:
|
||||||
|
return JsonResponse({'status': 404, 'error': 'La ruta no existe'}, status=404)
|
||||||
|
|
||||||
|
|
||||||
|
def tag_view(request, user_id):
|
||||||
|
"""
|
||||||
|
Punto de entrada para las vistas de tags
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Tiene que existir un usuario con el id entregado.
|
||||||
|
user = User.objects.filter(pk=user_id)
|
||||||
|
if user.count() != 1:
|
||||||
|
return JsonResponse({'status': 404, 'error': f'No existe un usuario con id {user_id}'}, status=404)
|
||||||
|
user = user[0]
|
||||||
|
|
||||||
|
if request.method == 'GET':
|
||||||
|
return _get_tags(request, user)
|
||||||
|
elif request.method == 'POST':
|
||||||
|
return _post_tag(request, user)
|
||||||
|
else:
|
||||||
|
return JsonResponse({'status': 404, 'error': 'La ruta no existe'}, status=404)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_list(request, user):
|
||||||
|
"""Retorna la lista de un usuario"""
|
||||||
|
|
||||||
|
encoded_list = []
|
||||||
|
for list_item in user.list.all():
|
||||||
|
encoded_list.append({
|
||||||
|
'entity': {
|
||||||
|
'mbid': list_item.entity.mbid,
|
||||||
|
'type': list_item.entity.entity_type,
|
||||||
|
},
|
||||||
|
'tags': [{
|
||||||
|
'id': tag.id,
|
||||||
|
'name': tag.name
|
||||||
|
} for tag in list_item.tags.all()]
|
||||||
|
})
|
||||||
|
|
||||||
|
return JsonResponse({'list': encoded_list})
|
||||||
|
|
||||||
|
|
||||||
|
@protected_resource()
|
||||||
|
def _add_to_list(request, user):
|
||||||
|
"""Agrega un nuevo item a la lista del usuario"""
|
||||||
|
|
||||||
|
# Solo el dueño o un administrador puede modificar la lista
|
||||||
|
if request.user.id != user.id and not request.user.is_admin:
|
||||||
|
return JsonResponse({'status': 403,
|
||||||
|
'error': 'El usuario no tiene permiso para hacer esta acción'},
|
||||||
|
status=403)
|
||||||
|
|
||||||
|
try:
|
||||||
|
request_data = json.loads(request.body.decode('utf8'))
|
||||||
|
except JSONDecodeError:
|
||||||
|
return JsonResponse({'status': 400,
|
||||||
|
'error': 'El body de la request no es json valido'},
|
||||||
|
status=400)
|
||||||
|
|
||||||
|
list_item = ListItem(user=user)
|
||||||
|
|
||||||
|
form = ListItemForm(request_data, instance=list_item)
|
||||||
|
|
||||||
|
if not form.is_valid():
|
||||||
|
return JsonResponse({'status': 400, 'error': form.errors.as_json()}, status=400)
|
||||||
|
|
||||||
|
if user.list.filter(entity__mbid=request_data['entity']).count() > 0:
|
||||||
|
return JsonResponse({'status': 400,
|
||||||
|
'error': 'El usuario ya tiene esta entidad en su lista'},
|
||||||
|
status=400)
|
||||||
|
|
||||||
|
form.save()
|
||||||
|
|
||||||
|
return JsonResponse({'status': 200})
|
||||||
|
|
||||||
|
|
||||||
|
def _get_list_item(request, user, list_item):
|
||||||
|
"""Obtiene un item de la lista del usuario"""
|
||||||
|
|
||||||
|
encoded_list_item = {
|
||||||
|
'entity': {
|
||||||
|
'mbid': list_item.entity.mbid,
|
||||||
|
'type': list_item.entity.entity_type,
|
||||||
|
},
|
||||||
|
'tags': [{
|
||||||
|
'id': tag.id,
|
||||||
|
'name': tag.name
|
||||||
|
} for tag in list_item.tags.all()]
|
||||||
|
}
|
||||||
|
|
||||||
|
return JsonResponse(encoded_list_item)
|
||||||
|
|
||||||
|
|
||||||
|
@protected_resource()
|
||||||
|
def _update_list_item(request, user, list_item):
|
||||||
|
# Solo el dueño o un administrador puede modificar la lista
|
||||||
|
if request.user.id != user.id and not request.user.is_admin:
|
||||||
|
return JsonResponse({'status': 403,
|
||||||
|
'error': 'El usuario no tiene permiso para hacer esta acción'},
|
||||||
|
status=403)
|
||||||
|
|
||||||
|
try:
|
||||||
|
request_data = json.loads(request.body.decode('utf8'))
|
||||||
|
except JSONDecodeError:
|
||||||
|
return JsonResponse({'status': 400,
|
||||||
|
'error': 'El body de la request no es json valido'},
|
||||||
|
status=400)
|
||||||
|
|
||||||
|
form = ListItemForm(request_data, instance=list_item)
|
||||||
|
|
||||||
|
if not form.is_valid():
|
||||||
|
return JsonResponse({'status': 400, 'error': form.errors.as_json()}, status=400)
|
||||||
|
|
||||||
|
form.save()
|
||||||
|
|
||||||
|
return JsonResponse({'status': 200})
|
||||||
|
|
||||||
|
|
||||||
|
@protected_resource()
|
||||||
|
def _remove_list_item(request, user, list_item):
|
||||||
|
"""Elimina un item de la lista del usuario"""
|
||||||
|
|
||||||
|
# Solo el dueño o un administrador puede modificar la lista
|
||||||
|
if request.user.id != user.id and not request.user.is_admin:
|
||||||
|
return JsonResponse({'status': 403,
|
||||||
|
'error': 'El usuario no tiene permiso para hacer esta acción'},
|
||||||
|
status=403)
|
||||||
|
|
||||||
|
list_item.delete()
|
||||||
|
|
||||||
|
return JsonResponse({'status': 200})
|
||||||
|
|
||||||
|
|
||||||
|
def _get_tags(request, user):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@protected_resource()
|
||||||
|
def _post_tag(request, user):
|
||||||
|
pass
|
||||||
@@ -32,6 +32,7 @@ INSTALLED_APPS = [
|
|||||||
'fetcher.apps.FetcherConfig',
|
'fetcher.apps.FetcherConfig',
|
||||||
'users.apps.UsersConfig',
|
'users.apps.UsersConfig',
|
||||||
'views.apps.ViewsConfig',
|
'views.apps.ViewsConfig',
|
||||||
|
'lists.apps.ListsConfig',
|
||||||
]
|
]
|
||||||
|
|
||||||
"""Middlewares on every call"""
|
"""Middlewares on every call"""
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ urlpatterns = [
|
|||||||
path('auth/', include('users.urls')),
|
path('auth/', include('users.urls')),
|
||||||
path('api/brainz/', include('fetcher.urls')),
|
path('api/brainz/', include('fetcher.urls')),
|
||||||
path('api/users/', include('users.api_urls')),
|
path('api/users/', include('users.api_urls')),
|
||||||
|
path('api/lists/', include('lists.urls')),
|
||||||
]
|
]
|
||||||
|
|
||||||
handler400 = 'views.views.handle400'
|
handler400 = 'views.views.handle400'
|
||||||
|
|||||||
@@ -3,21 +3,12 @@
|
|||||||
set -eu
|
set -eu
|
||||||
. .venv/bin/activate
|
. .venv/bin/activate
|
||||||
|
|
||||||
STASH_NAME=pre-commit-$(date +%s)
|
|
||||||
git stash save -q --keep-index $STASH_NAME
|
|
||||||
|
|
||||||
flake8 .
|
flake8 .
|
||||||
FLAKE_8=$?
|
FLAKE_8=$?
|
||||||
|
|
||||||
./test.sh
|
./test.sh
|
||||||
TEST=$?
|
TEST=$?
|
||||||
|
|
||||||
STASH_NUM=$(git stash list | grep $STASH_NAME | sed -re 's/stash@\{(.*)\}.*/\1/')
|
|
||||||
if [ -n "$STASH_NUM" ]; then
|
|
||||||
git stash pop -q stash@{$STASH_NUM}
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
if [ $FLAKE_8 -ne 0 ]; then
|
if [ $FLAKE_8 -ne 0 ]; then
|
||||||
exit $FLAKE_8
|
exit $FLAKE_8
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
[flake8]
|
[flake8]
|
||||||
max-line-length = 120
|
max-line-length = 120
|
||||||
exclude = __pycache__,.git,.idea,static,.venv,users/migrations/
|
exclude = __pycache__,.git,.idea,static,.venv,users/migrations/,lists/migrations/
|
||||||
|
|||||||
18
users/migrations/0002_auto_20200628_1836.py
Normal file
18
users/migrations/0002_auto_20200628_1836.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 3.0.7 on 2020-06-28 22:36
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('users', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelManagers(
|
||||||
|
name='user',
|
||||||
|
managers=[
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user