diff options
author | luxagraf <sng@luxagraf.net> | 2018-11-14 13:17:42 -0600 |
---|---|---|
committer | luxagraf <sng@luxagraf.net> | 2018-11-14 13:17:42 -0600 |
commit | a0b95dc2dfb84c682bb8f677e5d471f84e5028fe (patch) | |
tree | 6dd1919856f736c5b644270d59b57e4bb20336c5 /apps/notes |
wrote out basic notes skeleton
Diffstat (limited to 'apps/notes')
-rw-r--r-- | apps/notes/__init__.py | 0 | ||||
-rw-r--r-- | apps/notes/forms.py | 17 | ||||
-rw-r--r-- | apps/notes/migrations/0001_initial.py | 38 | ||||
-rw-r--r-- | apps/notes/migrations/0002_auto_20181111_1825.py | 31 | ||||
-rw-r--r-- | apps/notes/migrations/0003_note_folder.py | 19 | ||||
-rw-r--r-- | apps/notes/migrations/__init__.py | 0 | ||||
-rw-r--r-- | apps/notes/models.py | 38 | ||||
-rw-r--r-- | apps/notes/serializers.py | 18 | ||||
-rw-r--r-- | apps/notes/tests/__init__.py | 1 | ||||
-rw-r--r-- | apps/notes/tests/test_models.py | 30 | ||||
-rw-r--r-- | apps/notes/tests/test_views.py | 57 | ||||
-rw-r--r-- | apps/notes/urls.py | 18 | ||||
-rw-r--r-- | apps/notes/views.py | 41 |
13 files changed, 308 insertions, 0 deletions
diff --git a/apps/notes/__init__.py b/apps/notes/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/apps/notes/__init__.py diff --git a/apps/notes/forms.py b/apps/notes/forms.py new file mode 100644 index 0000000..6a27ec9 --- /dev/null +++ b/apps/notes/forms.py @@ -0,0 +1,17 @@ +from django import forms +from django.utils.translation import ugettext_lazy as _ + +from .models import Note + + +class NoteForm(forms.ModelForm): + class Meta: + model = Note + fields = ['title', 'body_markdown', 'url', 'tags'] + labels = { + "body_markdown": _("Note"), + } + + def __init__(self, *args, **kwargs): + self.user = kwargs.pop("user", None) + super(NoteForm, self).__init__(*args, **kwargs) diff --git a/apps/notes/migrations/0001_initial.py b/apps/notes/migrations/0001_initial.py new file mode 100644 index 0000000..3f04eb7 --- /dev/null +++ b/apps/notes/migrations/0001_initial.py @@ -0,0 +1,38 @@ +# Generated by Django 2.1.2 on 2018-11-11 18:01 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import taggit.managers + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('taggit', '0002_auto_20150616_2121'), + ] + + operations = [ + migrations.CreateModel( + name='Folder', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=250)), + ('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='Note', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=250)), + ('body_markdown', models.TextField(null=True)), + ('url', models.CharField(max_length=250)), + ('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ('tags', taggit.managers.TaggableManager(blank=True, help_text='Tags', through='taggit.TaggedItem', to='taggit.Tag', verbose_name='Tags')), + ], + ), + ] diff --git a/apps/notes/migrations/0002_auto_20181111_1825.py b/apps/notes/migrations/0002_auto_20181111_1825.py new file mode 100644 index 0000000..a7bc1c7 --- /dev/null +++ b/apps/notes/migrations/0002_auto_20181111_1825.py @@ -0,0 +1,31 @@ +# Generated by Django 2.1.2 on 2018-11-11 18:25 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('notes', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='note', + name='date_created', + field=models.DateTimeField(blank=True, default=datetime.datetime(2018, 11, 11, 18, 25, 29, 645561), editable=False), + preserve_default=False, + ), + migrations.AddField( + model_name='note', + name='date_updated', + field=models.DateTimeField(blank=True, default=datetime.datetime(2018, 11, 11, 18, 25, 42, 867666), editable=False), + preserve_default=False, + ), + migrations.AddField( + model_name='note', + name='slug', + field=models.SlugField(blank=True, unique=True), + ), + ] diff --git a/apps/notes/migrations/0003_note_folder.py b/apps/notes/migrations/0003_note_folder.py new file mode 100644 index 0000000..d548429 --- /dev/null +++ b/apps/notes/migrations/0003_note_folder.py @@ -0,0 +1,19 @@ +# Generated by Django 2.1.2 on 2018-11-14 15:41 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('notes', '0002_auto_20181111_1825'), + ] + + operations = [ + migrations.AddField( + model_name='note', + name='folder', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='notes.Folder'), + ), + ] diff --git a/apps/notes/migrations/__init__.py b/apps/notes/migrations/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/apps/notes/migrations/__init__.py diff --git a/apps/notes/models.py b/apps/notes/models.py new file mode 100644 index 0000000..aeb3bb3 --- /dev/null +++ b/apps/notes/models.py @@ -0,0 +1,38 @@ +from django.db import models +from django.utils import timezone +from django.template.defaultfilters import slugify + +from taggit.managers import TaggableManager + +from django.conf import settings + + +class Folder(models.Model): + created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) + name = models.CharField(max_length=250) + + def __str__(self): + return self.name + + +class Note(models.Model): + created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) + date_created = models.DateTimeField(blank=True, editable=False) + date_updated = models.DateTimeField(blank=True, editable=False) + title = models.CharField(max_length=250) + body_markdown = models.TextField(null=True) + url = models.CharField(max_length=250) + slug = models.SlugField(unique=True, blank=True) + folder = models.ForeignKey(Folder, null=True, on_delete=models.SET_NULL) + tags = TaggableManager(blank=True, help_text='Tags') + + def __str__(self): + return self.title + + def save(self, **kwargs): + # On save, update timestamps (users updated through admin.py) + if not self.id: + self.date_created = timezone.now() + self.slug = slugify(self.title)[:50] + self.date_updated = timezone.now() + super(Note, self).save() diff --git a/apps/notes/serializers.py b/apps/notes/serializers.py new file mode 100644 index 0000000..d6c7392 --- /dev/null +++ b/apps/notes/serializers.py @@ -0,0 +1,18 @@ +from rest_framework import serializers +from taggit_serializer.serializers import TagListSerializerField, TaggitSerializer + +from .models import Note, Folder + + +class NoteSerializer(TaggitSerializer, serializers.HyperlinkedModelSerializer): + tags = TagListSerializerField() + + class Meta: + model = Note + fields = ('title', 'body_markdown', 'url', 'folder', 'tags', 'date_created') + + +class FolderSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = Folder + fields = ('name') diff --git a/apps/notes/tests/__init__.py b/apps/notes/tests/__init__.py new file mode 100644 index 0000000..1d7ccb7 --- /dev/null +++ b/apps/notes/tests/__init__.py @@ -0,0 +1 @@ +from notes.tests import test_models, test_views diff --git a/apps/notes/tests/test_models.py b/apps/notes/tests/test_models.py new file mode 100644 index 0000000..e6cdb6a --- /dev/null +++ b/apps/notes/tests/test_models.py @@ -0,0 +1,30 @@ +from django.test import TestCase +from mixer.backend.django import mixer + +from notes.models import Note, Folder +from accounts.models import User + + +class FolderModelTest(TestCase): + + def test_string_representation(self): + user = mixer.blend(User, username='tpynchon') + folder = Folder(created_by=user, name="My Folder") + self.assertEqual(str(folder), "My Folder") + + +class NoteModelTest(TestCase): + + def test_string_representation(self): + user = mixer.blend(User, username='test') + note = Note( + created_by=user, + title="test note", + body_markdown="the body of the note", + url="https://luxagraf.net/", + tags="mine,cool site" + ) + self.assertEqual(str(note), "test note") + self.assertEqual(str(note.body_markdown), "the body of the note") + self.assertEqual(str(note.url), "https://luxagraf.net/") + self.assertEqual(str(note.tags), "mine,cool site") diff --git a/apps/notes/tests/test_views.py b/apps/notes/tests/test_views.py new file mode 100644 index 0000000..3f21b0b --- /dev/null +++ b/apps/notes/tests/test_views.py @@ -0,0 +1,57 @@ +import json +from django.test import Client +from django.test import RequestFactory, TestCase + +from rest_framework.test import force_authenticate +from rest_framework.test import APIRequestFactory +from mixer.backend.django import mixer + +from accounts.models import User +from notes.models import Note +from notes.views import NoteListView, NoteViewSet + + +class StoriesViewTest(TestCase): + def setUp(self): + # Every test needs access to the request factory. + self.factory = RequestFactory() + # test API with rest framework request factory. + self.apifactory = APIRequestFactory() + self.user = mixer.blend(User, username='tpynchon', password="gravity") + self.note = Note.objects.create( + created_by=self.user, + title="test note", + body_markdown="the body of the note", + url="https://luxagraf.net/", + ) + self.note.tags.add("mine,cool site") + self.note.save() + + def test_list_view(self): + request = self.factory.get('/%s/notes/' % (self.user.username)) + request.user = self.user + response = NoteListView.as_view()(request) + self.assertEqual(response.status_code, 200) + response.render() + + def test_api_list(self): + # Make an authenticated request to the view... + request = self.factory.get('/api/notes/') + force_authenticate(request, user=self.user) + response = NoteViewSet.as_view({'get': 'list'})(request) + self.assertEqual(response.status_code, 200) + response.render() + api_data = json.loads(response.content.decode('utf8'))[0] + self.assertEqual(api_data['title'], 'test note') + self.assertEqual(api_data['tags'], ['mine,cool site']) + + def test_api_(self): + # Make an authenticated request to the view... + request = self.factory.get('/api/notes/') + force_authenticate(request, user=self.user) + response = NoteViewSet.as_view({'get': 'list'})(request) + self.assertEqual(response.status_code, 200) + response.render() + api_data = json.loads(response.content.decode('utf8'))[0] + self.assertEqual(api_data['title'], 'test note') + self.assertEqual(api_data['tags'], ['mine,cool site']) diff --git a/apps/notes/urls.py b/apps/notes/urls.py new file mode 100644 index 0000000..76bdeb1 --- /dev/null +++ b/apps/notes/urls.py @@ -0,0 +1,18 @@ +from django.urls import path + +from . import views + +app_name = "notes" + +urlpatterns = [ + path( + r'create/', + views.NoteCreateView.as_view(), + name="note-create" + ), + path( + r'', + views.NoteListView.as_view(), + name="note" + ), +] diff --git a/apps/notes/views.py b/apps/notes/views.py new file mode 100644 index 0000000..ddb72ed --- /dev/null +++ b/apps/notes/views.py @@ -0,0 +1,41 @@ +from django.views.generic import CreateView, ListView, UpdateView, DeleteView +from django.views.generic.detail import DetailView +from django.utils.decorators import method_decorator +from django.contrib.auth.decorators import login_required + +from rest_framework import viewsets +from .serializers import NoteSerializer, FolderSerializer +from .models import Note +from .forms import NoteForm + + +@method_decorator(login_required, name='dispatch') +class LoggedInCreateViewWithUser(CreateView): + + def get_form_kwargs(self, **kwargs): + kwargs = super().get_form_kwargs(**kwargs) + kwargs.update({'user': self.request.user}) + return kwargs + + +class NoteListView(ListView): + model = Note + + def get_queryset(self): + return Note.objects.filter(created_by=self.request.user) + + +class NoteCreateView(LoggedInCreateViewWithUser): + model = Note + form_class = NoteForm + template_name = "notes/create.html" + + +class NoteViewSet(viewsets.ModelViewSet): + """ + API endpoint that allows users to be viewed or edited. + """ + serializer_class = NoteSerializer + + def get_queryset(self): + return Note.objects.filter(created_by=self.request.user).order_by('-date_created') |