1 # chloro - personal space
2 # Copyright (C) 2019 Frederic Peters
4 # This program is free software: you can redistribute it and/or modify it
5 # under the terms of the GNU Affero General Public License as published
6 # by the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Affero General Public License for more details.
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 from django.conf import settings
21 from django.contrib.syndication.views import Feed
22 from django.core.exceptions import PermissionDenied
23 from django.core.files.storage import default_storage
24 from django.http import HttpResponse, Http404, JsonResponse
25 from django.utils.feedgenerator import Atom1Feed
26 from django.views import View
27 from django.views.decorators.csrf import csrf_exempt
28 from django.views.generic import CreateView, DeleteView, DetailView, ListView, UpdateView, TemplateView
30 from sorl.thumbnail.shortcuts import get_thumbnail
32 from .models import Note
35 class NoteView(DetailView):
38 def get(self, request, *args, **kwargs):
39 note = self.get_object()
40 if kwargs.get('year'):
41 # check date does match
42 creation = self.get_object().creation_timestamp
43 if (creation.year, creation.month, creation.day) != (
49 if not note.published and not request.user.is_staff:
50 raise PermissionDenied()
51 return super(NoteView, self).get(request, *args, **kwargs)
54 class NoteEditView(UpdateView):
56 fields = ['title', 'slug', 'text', 'tags', 'published']
59 class NoteApiSaveView(View):
60 http_method_names = ['post']
62 def post(self, request, *args, **kwargs):
63 note = Note.objects.get(slug=kwargs['slug'])
64 note.text = request.POST['text']
66 return HttpResponse('ok')
69 class NoteAddView(CreateView):
71 fields = ['title', 'slug', 'text', 'tags', 'published']
74 class NoteDeleteView(DeleteView):
77 def get_success_url(self):
81 class HomeView(TemplateView):
82 template_name = 'phyll/home.html'
84 def get_context_data(self, **kwargs):
85 context = super(HomeView, self).get_context_data(**kwargs)
86 context['posts'] = Note.objects.filter(published=True).order_by('-creation_timestamp')[:5]
90 class ArchivesView(ListView):
93 def get_queryset(self):
94 qs = super(ArchivesView, self).get_queryset()
95 if not self.request.user.is_staff:
96 qs = qs.filter(published=True)
100 class ListOnTagView(ListView):
103 def get_queryset(self):
104 qs = Note.objects.filter(tags__name__in=[self.kwargs['tag']])
105 if not self.request.user.is_staff:
106 qs = qs.filter(published=True)
110 class Atom1FeedWithBaseXml(Atom1Feed):
111 def root_attributes(self):
112 root_attributes = super(Atom1FeedWithBaseXml, self).root_attributes()
113 scheme, netloc, path, params, query, fragment = urllib.parse.urlparse(self.feed['feed_url'])
114 root_attributes['xml:base'] = urllib.parse.urlunparse((scheme, netloc, '/', params, query, fragment))
115 return root_attributes
118 class AtomFeed(Feed):
119 title = settings.SITE_TITLE
121 feed_type = Atom1FeedWithBaseXml
122 author_name = settings.SITE_AUTHOR
124 def get_object(self, request, *args, **kwargs):
125 self.sub = kwargs.get('sub', 'default')
126 return super(AtomFeed, self).get_object(request, *args, **kwargs)
129 qs = Note.objects.filter(published=True)
130 if self.sub == 'default':
132 elif self.sub == 'gnome-en':
133 qs = qs.filter(tags__name__in=['gnome']).filter(tags__name__in=['lang-en'])
135 qs = qs.filter(tags__name__in=[self.sub])
136 return qs.select_related()[:20]
138 def item_description(self, item):
141 def item_guid(self, item):
142 for tag in item.tags.all():
143 if tag.name.startswith('old-post-id-'):
144 return 'http://www.0d.be/posts/%s' % tag.name.split('-')[-1]
145 return 'https://www.0d.be' + item.get_absolute_url()
147 def item_title(self, item):
150 def item_pubdate(self, item):
151 return item.creation_timestamp
155 def ajax_upload(request, *args, **kwargs):
156 upload = request.FILES['upload']
157 upload_path = 'uploads'
158 if os.path.splitext(upload.name.lower())[-1] in ('.jpg', '.jpeg', '.png', '.gif', '.svg'):
159 upload_path = 'images'
160 saved_path = default_storage.save('%s/%s' % (upload_path, upload.name), upload)
161 url = '/media/' + saved_path
162 response = {'url': url, 'filename': upload.name}
163 if upload_path == 'images':
164 if default_storage.size(saved_path) > 500_000 and not upload.name.endswith('.svg'):
165 response['orig_url'] = url
167 response['url'] = get_thumbnail(saved_path, '1000', upscale=False).url
170 return JsonResponse(response)