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 | ␊ |
37 | def getPreference(self, name):␊ |
38 | if name == 'hidden_categories':␊ |
39 | return HttpResponse('{"hidden_categories" : [' + self.hidden_categories + ']}', 'application/json')␊ |
40 | else:␊ |
41 | raise Http404␊ |
42 | ␊ |
43 | def setPreference(self, name, value):␊ |
44 | if name == 'hidden_categories':␊ |
45 | categories = []␊ |
46 | for c in value.split(','):␊ |
47 | if c == '-1' or \␊ |
48 | (c and Category.objects.filter(id=c).exists()):␊ |
49 | categories.append(c)␊ |
50 | self.hidden_categories = ','.join(categories)␊ |
51 | self.save()␊ |
52 | return HttpResponse('')␊ |
53 | else:␊ |
54 | raise Http404␊ |
55 | ␊ |
56 | class Category(models.Model):␊ |
57 | author = models.ForeignKey(User, null=True, on_delete=models.CASCADE)␊ |
58 | name = models.CharField(max_length=50, unique=True, blank=False)␊ |
59 | ␊ |
60 | class Note(models.Model):␊ |
61 | author = models.ForeignKey(User, null=False, on_delete=models.CASCADE)␊ |
62 | title = models.CharField(max_length=100, blank=False)␊ |
63 | long_summary = models.CharField(max_length=255)␊ |
64 | short_summary = models.CharField(max_length=255)␊ |
65 | text = models.TextField(blank=False)␊ |
66 | transformed_text = models.TextField()␊ |
67 | created_date = models.DateTimeField()␊ |
68 | modified_date = models.DateTimeField()␊ |
69 | visibility = models.IntegerField(default=0)␊ |
70 | category = models.ForeignKey(Category, null=True, on_delete=models.SET_NULL)␊ |
71 | ␊ |
72 | def _wrap(self, text, limit, max_limit):␊ |
73 | if len(text) < limit: return text␊ |
74 | ␊ |
75 | lower_limit = upper_limit = limit␊ |
76 | ␊ |
77 | while text[lower_limit-1] != ' ' and\␊ |
78 | lower_limit > 1:␊ |
79 | lower_limit -= 1␊ |
80 | ␊ |
81 | while text[upper_limit-1] != ' ' and\␊ |
82 | upper_limit < len(text):␊ |
83 | upper_limit += 1␊ |
84 | ␊ |
85 | lower = limit - lower_limit␊ |
86 | upper = upper_limit - limit␊ |
87 | ␊ |
88 | if lower > max_limit and upper > max_limit:␊ |
89 | cur_limit = limit + max_limit␊ |
90 | else:␊ |
91 | if lower < upper:␊ |
92 | cur_limit = limit - lower␊ |
93 | else:␊ |
94 | cur_limit = limit + upper␊ |
95 | ␊ |
96 | if cur_limit and text[cur_limit-1] == ' ':␊ |
97 | cur_limit -= 1␊ |
98 | ␊ |
99 | return text[:cur_limit] + '...'␊ |
100 | ␊ |
101 | def _summarize(self):␊ |
102 | # Remove markup␊ |
103 | self.long_summary = re.sub(r'<[^>]+>', '', self.transformed_text)␊ |
104 | self.long_summary = re.sub(r'&[^;]+;', '', self.long_summary)␊ |
105 | # Remove return␊ |
106 | self.long_summary = re.sub(r'\n', ' ', self.long_summary)␊ |
107 | self.long_summary = re.sub(r'\r', ' ', self.long_summary)␊ |
108 | # Remove duplicated spaces␊ |
109 | self.long_summary = re.sub(r' [ ]+', ' ', self.long_summary)␊ |
110 | self.long_summary = self.long_summary.strip()␊ |
111 | self.short_summary = self.long_summary[:]␊ |
112 | ␊ |
113 | self.long_summary = self._wrap(self.long_summary, 100, 5)␊ |
114 | self.short_summary = self._wrap(self.short_summary, 30, 5)␊ |
115 | ␊ |
116 | def save(self):␊ |
117 | self.modified_date = datetime.now()␊ |
118 | self.transformed_text = markdown2.markdown(self.text, extras=['fenced-code-blocks'])␊ |
119 | self._summarize()␊ |
120 | s = Search()␊ |
121 | ␊ |
122 | super(Note, self).save()␊ |
123 | ␊ |
124 | @receiver(post_save, sender=Note)␊ |
125 | def post_save_note_signal(sender, **kwargs):␊ |
126 | s = Search()␊ |
127 | s.edit_note(kwargs['instance'].id)␊ |
128 | ␊ |
129 | @receiver(pre_delete, sender=Note)␊ |
130 | def pre_delete_note_signal(sender, **kwargs):␊ |
131 | s = Search()␊ |
132 | s.delete_note(kwargs['instance'].id)␊ |
133 | ␊ |
134 | def manage_category(user, cat_name):␊ |
135 | category = None␊ |
136 | if cat_name:␊ |
137 | category = Category.objects.filter(name=cat_name)␊ |
138 | # Create a new one␊ |
139 | if not category:␊ |
140 | if len(cat_name) > 50: cat_name = cat_name[:50]␊ |
141 | category = Category(author=user, name=cat_name)␊ |
142 | category.save()␊ |
143 | else:␊ |
144 | category = category[0]␊ |
145 | return category␊ |