1 | # -*- coding: utf-8 -*-␊ |
2 | """␊ |
3 | Copyright 2015 Grégory Soutadé␊ |
4 | ␊ |
5 | This file is part of Dénote.␊ |
6 | ␊ |
7 | Dénote is free software: you can redistribute it and/or modify␊ |
8 | it under the terms of the GNU General Public License as published by␊ |
9 | the Free Software Foundation, either version 3 of the License, or␊ |
10 | (at your option) any later version.␊ |
11 | ␊ |
12 | Dénote is distributed in the hope that it will be useful,␊ |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of␊ |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the␊ |
15 | GNU General Public License for more details.␊ |
16 | ␊ |
17 | You should have received a copy of the GNU General Public License␊ |
18 | along with Dénote. If not, see <http://www.gnu.org/licenses/>.␊ |
19 | """␊ |
20 | ␊ |
21 | from datetime import datetime␊ |
22 | import re␊ |
23 | ␊ |
24 | from django.db import models␊ |
25 | from django.contrib.auth.models import AbstractUser␊ |
26 | from django.http import HttpResponse␊ |
27 | from django.db.models.signals import pre_init, post_init, pre_delete, post_delete␊ |
28 | from django.db.models.signals import pre_save, post_save␊ |
29 | from django.dispatch import receiver␊ |
30 | ␊ |
31 | import markdown2␊ |
32 | from search import Search␊ |
33 | ␊ |
34 | class User(AbstractUser):␊ |
35 | hidden_categories = models.TextField(blank=True)␊ |
36 | home_notes_visibility = models.IntegerField(default=0, choices=[(0, 'private'), (1, 'registered'), (2, 'public')])␊ |
37 | default_template = models.ForeignKey('Template', null=True, on_delete=models.SET_NULL)␊ |
38 | ␊ |
39 | def getPreference(self, name):␊ |
40 | if name == 'hidden_categories':␊ |
41 | return HttpResponse('{"hidden_categories" : [' + self.hidden_categories + ']}', 'application/json')␊ |
42 | else:␊ |
43 | raise Http404␊ |
44 | ␊ |
45 | def setPreference(self, name, value):␊ |
46 | if name == 'hidden_categories':␊ |
47 | categories = []␊ |
48 | for c in value.split(','):␊ |
49 | if c == '-1' or \␊ |
50 | (c and Category.objects.filter(id=c).exists()):␊ |
51 | categories.append(c)␊ |
52 | self.hidden_categories = ','.join(categories)␊ |
53 | self.save()␊ |
54 | return HttpResponse('')␊ |
55 | else:␊ |
56 | raise Http404␊ |
57 | ␊ |
58 | class Category(models.Model):␊ |
59 | author = models.ForeignKey(User, null=True, on_delete=models.CASCADE)␊ |
60 | name = models.CharField(max_length=50, unique=True, blank=False)␊ |
61 | ␊ |
62 | class Note(models.Model):␊ |
63 | ␊ |
64 | PRIVATE = 0␊ |
65 | REGISTERED = 1␊ |
66 | PUBLIC = 2␊ |
67 | ␊ |
68 | VISIBILITY = ((PRIVATE, 'Private'),␊ |
69 | (REGISTERED, 'Registered'),␊ |
70 | (PUBLIC, 'Public')␊ |
71 | )␊ |
72 | ␊ |
73 | author = models.ForeignKey(User, null=False, on_delete=models.CASCADE)␊ |
74 | title = models.CharField(max_length=100, blank=False)␊ |
75 | long_summary = models.CharField(max_length=255)␊ |
76 | short_summary = models.CharField(max_length=255)␊ |
77 | text = models.TextField(blank=False)␊ |
78 | transformed_text = models.TextField()␊ |
79 | created_date = models.DateTimeField()␊ |
80 | modified_date = models.DateTimeField()␊ |
81 | visibility = models.IntegerField(default=PRIVATE, choices=VISIBILITY)␊ |
82 | category = models.ForeignKey(Category, null=True, on_delete=models.SET_NULL)␊ |
83 | ␊ |
84 | def _wrap(self, text, limit, max_limit):␊ |
85 | if len(text) < limit: return text␊ |
86 | ␊ |
87 | lower_limit = upper_limit = limit␊ |
88 | ␊ |
89 | while text[lower_limit-1] != ' ' and\␊ |
90 | lower_limit > 1:␊ |
91 | lower_limit -= 1␊ |
92 | ␊ |
93 | while text[upper_limit-1] != ' ' and\␊ |
94 | upper_limit < len(text):␊ |
95 | upper_limit += 1␊ |
96 | ␊ |
97 | lower = limit - lower_limit␊ |
98 | upper = upper_limit - limit␊ |
99 | ␊ |
100 | if lower > max_limit and upper > max_limit:␊ |
101 | cur_limit = limit + max_limit␊ |
102 | else:␊ |
103 | if lower < upper:␊ |
104 | cur_limit = limit - lower␊ |
105 | else:␊ |
106 | cur_limit = limit + upper␊ |
107 | ␊ |
108 | if cur_limit and text[cur_limit-1] == ' ':␊ |
109 | cur_limit -= 1␊ |
110 | ␊ |
111 | return text[:cur_limit] + '...'␊ |
112 | ␊ |
113 | def _summarize(self):␊ |
114 | # Remove markup␊ |
115 | self.long_summary = re.sub(r'<[^>]+>', '', self.transformed_text)␊ |
116 | self.long_summary = re.sub(r'&[^;]+;', '', self.long_summary)␊ |
117 | # Remove return␊ |
118 | self.long_summary = re.sub(r'\n', ' ', self.long_summary)␊ |
119 | self.long_summary = re.sub(r'\r', ' ', self.long_summary)␊ |
120 | # Remove duplicated spaces␊ |
121 | self.long_summary = re.sub(r' [ ]+', ' ', self.long_summary)␊ |
122 | self.long_summary = self.long_summary.strip()␊ |
123 | self.short_summary = self.long_summary[:]␊ |
124 | ␊ |
125 | self.long_summary = self._wrap(self.long_summary, 100, 5)␊ |
126 | self.short_summary = self._wrap(self.short_summary, 30, 5)␊ |
127 | ␊ |
128 | def save(self):␊ |
129 | self.modified_date = datetime.now()␊ |
130 | self.transformed_text = markdown2.markdown(self.text, extras=['fenced-code-blocks'])␊ |
131 | self._summarize()␊ |
132 | s = Search()␊ |
133 | ␊ |
134 | super(Note, self).save()␊ |
135 | ␊ |
136 | class Template(models.Model):␊ |
137 | name = models.CharField(max_length=30, blank=False, unique=True)␊ |
138 | ␊ |
139 | author = models.ForeignKey(User, null=False, on_delete=models.CASCADE)␊ |
140 | title = models.CharField(max_length=100, blank=True)␊ |
141 | text = models.TextField(blank=True)␊ |
142 | visibility = models.IntegerField(default=Note.PRIVATE, choices=Note.VISIBILITY)␊ |
143 | category = models.ForeignKey(Category, null=True, on_delete=models.SET_NULL)␊ |
144 | ␊ |
145 | @receiver(post_save, sender=Note)␊ |
146 | def post_save_note_signal(sender, **kwargs):␊ |
147 | s = Search()␊ |
148 | if kwargs['created']:␊ |
149 | s.index_note(kwargs['instance'].id)␊ |
150 | else:␊ |
151 | s.edit_note(kwargs['instance'].id)␊ |
152 | ␊ |
153 | @receiver(pre_delete, sender=Note)␊ |
154 | def pre_delete_note_signal(sender, **kwargs):␊ |
155 | s = Search()␊ |
156 | s.delete_note(kwargs['instance'].id)␊ |
157 | ␊ |
158 | def manage_category(user, cat_name):␊ |
159 | category = None␊ |
160 | if cat_name:␊ |
161 | category = Category.objects.filter(name=cat_name)␊ |
162 | # Create a new one␊ |
163 | if not category:␊ |
164 | if len(cat_name) > 50: cat_name = cat_name[:50]␊ |
165 | category = Category(author=user, name=cat_name)␊ |
166 | category.save()␊ |
167 | else:␊ |
168 | category = category[0]␊ |
169 | return category␊ |