Commit | Line | Data |
---|---|---|
8e1e744d | 1 | # GNU MediaGoblin -- federated, autonomous media hosting |
e5572c60 ML |
2 | # Copyright (C) 2011 Free Software Foundation, Inc |
3 | # | |
4 | # This program is free software: you can redistribute it and/or modify | |
5 | # it under the terms of the GNU Affero General Public License as published by | |
6 | # the Free Software Foundation, either version 3 of the License, or | |
7 | # (at your option) any later version. | |
8 | # | |
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. | |
13 | # | |
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/>. | |
16 | ||
db1a438f | 17 | import datetime, uuid |
4ad5af85 | 18 | |
d232e0f6 | 19 | from mongokit import Document, Set |
4329be14 | 20 | |
0546833c | 21 | from mediagoblin import util |
4ad5af85 | 22 | from mediagoblin.auth import lib as auth_lib |
6e7ce8d1 | 23 | from mediagoblin import mg_globals |
757f37a5 | 24 | from mediagoblin.db import migrations |
9c0fe63f | 25 | from mediagoblin.db.util import ASCENDING, DESCENDING, ObjectId |
7bd8197f | 26 | from mediagoblin.util import Pagination |
d232e0f6 | 27 | |
7bf3f5db CAW |
28 | ################### |
29 | # Custom validators | |
30 | ################### | |
31 | ||
32 | ######## | |
33 | # Models | |
34 | ######## | |
35 | ||
36 | ||
d232e0f6 | 37 | class User(Document): |
73a6e206 CAW |
38 | __collection__ = 'users' |
39 | ||
d232e0f6 CAW |
40 | structure = { |
41 | 'username': unicode, | |
24181820 | 42 | 'email': unicode, |
d232e0f6 CAW |
43 | 'created': datetime.datetime, |
44 | 'plugin_data': dict, # plugins can dump stuff here. | |
45 | 'pw_hash': unicode, | |
24181820 | 46 | 'email_verified': bool, |
4d75522b | 47 | 'status': unicode, |
18cf34d4 CAW |
48 | 'verification_key': unicode, |
49 | 'is_admin': bool, | |
630b57a3 | 50 | 'url' : unicode, |
279d925e | 51 | 'bio' : unicode |
d232e0f6 CAW |
52 | } |
53 | ||
db5912e3 | 54 | required_fields = ['username', 'created', 'pw_hash', 'email'] |
fc9bb821 CAW |
55 | |
56 | default_values = { | |
24181820 | 57 | 'created': datetime.datetime.utcnow, |
4d75522b | 58 | 'email_verified': False, |
db1a438f | 59 | 'status': u'needs_email_verification', |
18cf34d4 CAW |
60 | 'verification_key': lambda: unicode(uuid.uuid4()), |
61 | 'is_admin': False} | |
0472653e | 62 | |
63 | migration_handler = migrations.UserMigration | |
fc9bb821 | 64 | |
4ad5af85 CAW |
65 | def check_login(self, password): |
66 | """ | |
67 | See if a user can login with this password | |
68 | """ | |
69 | return auth_lib.bcrypt_check_password( | |
70 | password, self['pw_hash']) | |
71 | ||
d232e0f6 | 72 | |
4d75522b CAW |
73 | class MediaEntry(Document): |
74 | __collection__ = 'media_entries' | |
75 | ||
76 | structure = { | |
757f37a5 | 77 | 'uploader': ObjectId, |
4d75522b | 78 | 'title': unicode, |
1013bdaf | 79 | 'slug': unicode, |
4d75522b | 80 | 'created': datetime.datetime, |
44e2da2f JW |
81 | 'description': unicode, # May contain markdown/up |
82 | 'description_html': unicode, # May contain plaintext, or HTML | |
4d75522b CAW |
83 | 'media_type': unicode, |
84 | 'media_data': dict, # extra data relevant to this media_type | |
85 | 'plugin_data': dict, # plugins can dump stuff here. | |
74ae6b11 CAW |
86 | 'tags': [unicode], |
87 | 'state': unicode, | |
88 | ||
fa7f9c61 CAW |
89 | # For now let's assume there can only be one main file queued |
90 | # at a time | |
91 | 'queued_media_file': [unicode], | |
92 | ||
93 | # A dictionary of logical names to filepaths | |
94 | 'media_files': dict, | |
95 | ||
74ae6b11 CAW |
96 | # The following should be lists of lists, in appropriate file |
97 | # record form | |
74ae6b11 | 98 | 'attachment_files': list, |
74ae6b11 CAW |
99 | |
100 | # This one should just be a single file record | |
101 | 'thumbnail_file': [unicode]} | |
4d75522b CAW |
102 | |
103 | required_fields = [ | |
b1ae76ae | 104 | 'uploader', 'created', 'media_type', 'slug'] |
4d75522b CAW |
105 | |
106 | default_values = { | |
74ae6b11 CAW |
107 | 'created': datetime.datetime.utcnow, |
108 | 'state': u'unprocessed'} | |
4d75522b | 109 | |
757f37a5 CAW |
110 | migration_handler = migrations.MediaEntryMigration |
111 | ||
4d75522b CAW |
112 | def main_mediafile(self): |
113 | pass | |
7bd8197f JW |
114 | |
115 | def get_comments(self, page): | |
116 | cursor = self.db.MediaComment.find({ | |
117 | 'media_entry': self['_id']}).sort('created', DESCENDING) | |
118 | ||
119 | pagination = Pagination(page, cursor) | |
120 | comments = pagination() | |
121 | ||
122 | data = list() | |
123 | for comment in comments: | |
124 | comment['author'] = self.db.User.find_one({ | |
125 | '_id': comment['author']}) | |
126 | data.append(comment) | |
127 | ||
128 | return (data, pagination) | |
129 | ||
0546833c AW |
130 | def generate_slug(self): |
131 | self['slug'] = util.slugify(self['title']) | |
132 | ||
6e7ce8d1 | 133 | duplicate = mg_globals.database.media_entries.find_one( |
f0545dde | 134 | {'slug': self['slug']}) |
0546833c AW |
135 | |
136 | if duplicate: | |
137 | self['slug'] = "%s-%s" % (self['_id'], self['slug']) | |
4d75522b | 138 | |
6926b23d CAW |
139 | def url_for_self(self, urlgen): |
140 | """ | |
141 | Generate an appropriate url for ourselves | |
142 | ||
143 | Use a slug if we have one, else use our '_id'. | |
144 | """ | |
16509be1 CAW |
145 | uploader = self.uploader() |
146 | ||
6926b23d CAW |
147 | if self.get('slug'): |
148 | return urlgen( | |
149 | 'mediagoblin.user_pages.media_home', | |
16509be1 | 150 | user=uploader['username'], |
6926b23d CAW |
151 | media=self['slug']) |
152 | else: | |
153 | return urlgen( | |
154 | 'mediagoblin.user_pages.media_home', | |
16509be1 | 155 | user=uploader['username'], |
6926b23d | 156 | media=unicode(self['_id'])) |
9c0fe63f CFD |
157 | |
158 | def url_to_prev(self, urlgen): | |
159 | """ | |
160 | Provide a url to the previous entry from this user, if there is one | |
161 | """ | |
162 | cursor = self.db.MediaEntry.find({'_id' : {"$lt": self['_id']}, | |
163 | 'uploader': self['uploader']}).sort( | |
164 | '_id', DESCENDING).limit(1) | |
165 | ||
166 | if cursor.count(): | |
167 | return urlgen('mediagoblin.user_pages.media_home', | |
168 | user=self.uploader()['username'], | |
169 | media=unicode(cursor[0]['_id'])) | |
170 | ||
171 | def url_to_next(self, urlgen): | |
172 | """ | |
173 | Provide a url to the next entry from this user, if there is one | |
174 | """ | |
175 | cursor = self.db.MediaEntry.find({'_id' : {"$gt": self['_id']}, | |
176 | 'uploader': self['uploader']}).sort( | |
177 | '_id', ASCENDING).limit(1) | |
178 | ||
179 | if cursor.count(): | |
180 | return urlgen('mediagoblin.user_pages.media_home', | |
181 | user=self.uploader()['username'], | |
182 | media=unicode(cursor[0]['_id'])) | |
6926b23d | 183 | |
16509be1 CAW |
184 | def uploader(self): |
185 | return self.db.User.find_one({'_id': self['uploader']}) | |
186 | ||
c11f21ab JW |
187 | class MediaComment(Document): |
188 | __collection__ = 'media_comments' | |
6926b23d | 189 | |
c11f21ab JW |
190 | structure = { |
191 | 'media_entry': ObjectId, | |
192 | 'author': ObjectId, | |
193 | 'created': datetime.datetime, | |
194 | 'content': unicode, | |
195 | 'content_html': unicode} | |
196 | ||
197 | required_fields = [ | |
7bd8197f | 198 | 'media_entry', 'author', 'created', 'content'] |
c11f21ab JW |
199 | |
200 | default_values = { | |
201 | 'created': datetime.datetime.utcnow} | |
202 | ||
203 | def media_entry(self): | |
7bd8197f | 204 | return self.db.MediaEntry.find_one({'_id': self['media_entry']}) |
c11f21ab JW |
205 | |
206 | def author(self): | |
207 | return self.db.User.find_one({'_id': self['author']}) | |
6926b23d | 208 | |
c11f21ab JW |
209 | REGISTER_MODELS = [ |
210 | MediaEntry, | |
211 | User, | |
212 | MediaComment] | |
d232e0f6 | 213 | |
4329be14 | 214 | |
d232e0f6 CAW |
215 | def register_models(connection): |
216 | """ | |
217 | Register all models in REGISTER_MODELS with this connection. | |
218 | """ | |
db61f7d1 CAW |
219 | connection.register(REGISTER_MODELS) |
220 |