Compare commits

...

10 Commits

Author SHA1 Message Date
b622fd4121 Add .vscode to gitignore 2021-11-03 21:47:11 -05:00
788eb99dcd Load and output sass 2021-04-29 21:00:52 -05:00
dcf99e5409 More progress in webpack guides 2021-04-08 09:05:11 -05:00
cf8885ed14 Start frontend project 2021-04-07 21:23:37 -05:00
e04e991cfa Start frontend project 2021-04-07 21:23:21 -05:00
b46ec965e1 Allow token and session auth 2021-04-05 20:48:14 -05:00
0793242dfe Fix bookmarks api routes 2021-04-01 21:01:42 -05:00
da85e74860 Install and use djangorestframework 2021-04-01 20:36:29 -05:00
567226684d Bookmark form 2021-04-01 09:30:10 -05:00
1154b14e62 Filter bookmarks by user 2021-03-31 09:33:50 -05:00
21 changed files with 5311 additions and 8 deletions

8
.gitignore vendored
View File

@@ -135,4 +135,10 @@ dmypy.json
.pytype/
# Cython debug symbols
cython_debug/
cython_debug/
# npm
node_modules/
# vscode
.vscode

0
apiv1/__init__.py Normal file
View File

3
apiv1/admin.py Normal file
View File

@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

5
apiv1/apps.py Normal file
View File

@@ -0,0 +1,5 @@
from django.apps import AppConfig
class Apiv1Config(AppConfig):
name = 'apiv1'

View File

7
apiv1/models.py Normal file
View File

@@ -0,0 +1,7 @@
from rest_framework import serializers
from bookmarks.models import Bookmark
class BookmarkSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Bookmark
fields = ['title', 'url', 'id']

3
apiv1/tests.py Normal file
View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

15
apiv1/urls.py Normal file
View File

@@ -0,0 +1,15 @@
from django.urls import include, path
from rest_framework import routers, authtoken
from rest_framework.authtoken import views as authtokenviews
from . import views
router = routers.DefaultRouter()
router.register(r'bookmarks', views.BookmarkViewSet, basename='bookmark')
# Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browsable API.
urlpatterns = [
path('', include(router.urls)),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
path('token/', authtokenviews.obtain_auth_token),
]

13
apiv1/views.py Normal file
View File

@@ -0,0 +1,13 @@
from rest_framework import viewsets
from . import models
from bookmarks.models import Bookmark
class BookmarkViewSet(viewsets.ModelViewSet):
serializer_class = models.BookmarkSerializer
def perform_create(self, serializer):
serializer.save(user = self.request.user)
def get_queryset(self):
return Bookmark.objects.filter(user=self.request.user)

View File

@@ -0,0 +1,6 @@
<h1>Add a bookmark</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Save">
</form>

View File

@@ -4,5 +4,6 @@ from . import views
app_name = 'bookmarks'
urlpatterns = [
path('', views.BookmarkListView.as_view(), name='bookmark-list')
path('', views.BookmarkListView.as_view(), name='bookmark-list'),
path('create', views.BookmarkCreate.as_view(), name='bookmark-create')
]

View File

@@ -1,5 +1,7 @@
from django.utils import timezone
from .models import Bookmark
from django.urls import reverse_lazy
from django.views.generic.list import ListView
from django.views.generic import CreateView
from django.contrib.auth.mixins import LoginRequiredMixin
from .models import Bookmark
@@ -8,7 +10,14 @@ class BookmarkListView(LoginRequiredMixin, ListView):
model = Bookmark
paginate_by = 20
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['now'] = timezone.now()
return context
def get_queryset(self):
return Bookmark.objects.filter(user_id=self.request.user.id)
class BookmarkCreate(LoginRequiredMixin, CreateView):
model = Bookmark
fields = ['title','url']
success_url = reverse_lazy('bookmarks:bookmark-list')
def form_valid(self, form):
form.instance.user = self.request.user
return super().form_valid(form)

View File

@@ -0,0 +1,3 @@
body {
background-color: black;
}

View File

@@ -32,12 +32,15 @@ ALLOWED_HOSTS = []
INSTALLED_APPS = [
'bookmarks.apps.BookmarksConfig',
'apiv1.apps.Apiv1Config',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'rest_framework.authtoken'
]
MIDDLEWARE = [
@@ -121,3 +124,17 @@ USE_TZ = True
# https://docs.djangoproject.com/en/3.1/howto/static-files/
STATIC_URL = '/static/'
REST_FRAMEWORK = {
# Use Django's standard `django.contrib.auth` permissions,
# or allow read-only access for unauthenticated users.
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated'
],
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 100,
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
]
}

View File

@@ -1,6 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>Forget me not</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
{% block content %} {% endblock %}

View File

@@ -22,5 +22,6 @@ urlpatterns = [
path('', views.home, name='home'),
path('bookmarks/', include('bookmarks.urls')),
path('admin/', admin.site.urls),
path('accounts/', include('django.contrib.auth.urls'))
path('accounts/', include('django.contrib.auth.urls')),
path('api/v1/', include('apiv1.urls')),
]

5130
frontend/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

30
frontend/package.json Normal file
View File

@@ -0,0 +1,30 @@
{
"name": "frontend",
"version": "1.0.0",
"description": "",
"private": true,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"watch": "webpack --watch",
"start": "webpack serve --open",
"build": "webpack --env production"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"css-loader": "^5.2.0",
"html-webpack-plugin": "^5.3.1",
"mini-css-extract-plugin": "^1.5.1",
"sass": "^1.32.12",
"sass-loader": "^11.0.1",
"style-loader": "^2.0.0",
"webpack": "^5.31.0",
"webpack-cli": "^4.6.0",
"webpack-dev-middleware": "^4.1.0",
"webpack-dev-server": "^3.11.2"
},
"dependencies": {
"lodash": "^4.17.21"
}
}

1
frontend/src/styles.scss Normal file
View File

@@ -0,0 +1 @@
@import '../../forgetmenot/frontend/styles.scss';

View File

@@ -0,0 +1,50 @@
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = (env) => {
return {
mode: env.production ? "production" : "development",
entry: "./src/styles.scss",
devtool: "inline-source-map",
devServer: {
contentBase: "./dist",
},
plugins: [
new HtmlWebpackPlugin({
title: "Caching",
}),
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css",
}),
],
output: {
filename: "[name].[contenthash].js",
path: path.resolve(__dirname, "dist"),
clean: true,
publicPath: "/",
},
module: {
rules: [
{
test: /\.s[ac]ss/i,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
},
],
},
optimization: {
moduleIds: "deterministic",
runtimeChunk: "single",
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: "vendors",
chunks: "all",
},
},
},
},
};
};

Binary file not shown.