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