Create a fully functional get_comments for SQL
[mediagoblin.git] / mediagoblin / db / sql / models.py
1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011,2012 MediaGoblin contributors. See AUTHORS.
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
17
18 import datetime
19
20 from sqlalchemy.ext.declarative import declarative_base
21 from sqlalchemy import (
22 Column, Integer, Unicode, UnicodeText, DateTime, Boolean, ForeignKey,
23 UniqueConstraint)
24 from sqlalchemy.orm import relationship
25 from sqlalchemy.orm.collections import attribute_mapped_collection
26 from sqlalchemy.ext.associationproxy import association_proxy
27
28 from mediagoblin.db.sql.extratypes import PathTupleWithSlashes
29 from mediagoblin.db.sql.base import GMGTableBase
30 from mediagoblin.db.mixin import UserMixin, MediaEntryMixin
31
32
33 Base = declarative_base(cls=GMGTableBase)
34
35
36 class SimpleFieldAlias(object):
37 """An alias for any field"""
38 def __init__(self, fieldname):
39 self.fieldname = fieldname
40
41 def __get__(self, instance, cls):
42 return getattr(instance, self.fieldname)
43
44 def __set__(self, instance, val):
45 setattr(instance, self.fieldname, val)
46
47
48 class User(Base, UserMixin):
49 __tablename__ = "users"
50
51 id = Column(Integer, primary_key=True)
52 username = Column(Unicode, nullable=False, unique=True)
53 email = Column(Unicode, nullable=False)
54 created = Column(DateTime, nullable=False, default=datetime.datetime.now)
55 pw_hash = Column(Unicode, nullable=False)
56 email_verified = Column(Boolean)
57 status = Column(Unicode, default=u"needs_email_verification", nullable=False)
58 verification_key = Column(Unicode)
59 is_admin = Column(Boolean, default=False, nullable=False)
60 url = Column(Unicode)
61 bio = Column(UnicodeText) # ??
62 bio_html = Column(UnicodeText) # ??
63 fp_verification_key = Column(Unicode)
64 fp_token_expire = Column(DateTime)
65
66 ## TODO
67 # plugin data would be in a separate model
68
69 _id = SimpleFieldAlias("id")
70
71
72 class MediaEntry(Base, MediaEntryMixin):
73 __tablename__ = "media_entries"
74
75 id = Column(Integer, primary_key=True)
76 uploader = Column(Integer, ForeignKey('users.id'), nullable=False)
77 title = Column(Unicode, nullable=False)
78 slug = Column(Unicode, nullable=False)
79 created = Column(DateTime, nullable=False, default=datetime.datetime.now)
80 description = Column(UnicodeText) # ??
81 description_html = Column(UnicodeText) # ??
82 media_type = Column(Unicode, nullable=False)
83 state = Column(Unicode, nullable=False) # or use sqlalchemy.types.Enum?
84 license = Column(Unicode)
85
86 fail_error = Column(Unicode)
87 fail_metadata = Column(UnicodeText)
88
89 queued_media_file = Column(PathTupleWithSlashes)
90
91 queued_task_id = Column(Unicode)
92
93 __table_args__ = (
94 UniqueConstraint('uploader', 'slug'),
95 {})
96
97 get_uploader = relationship(User)
98
99 media_files_helper = relationship("MediaFile",
100 collection_class=attribute_mapped_collection("name"),
101 cascade="all, delete-orphan"
102 )
103 media_files = association_proxy('media_files_helper', 'file_path',
104 creator=lambda k, v: MediaFile(name=k, file_path=v)
105 )
106
107 ## TODO
108 # media_data
109 # attachment_files
110 # fail_error
111
112 def get_comments(self, ascending=False):
113 order_col = MediaComment.created
114 if not ascending:
115 order_col = desc(order_col)
116 return MediaComment.query.filter_by(
117 media_entry=self.id).order_by(order_col)
118
119
120 class MediaFile(Base):
121 __tablename__ = "mediafiles"
122
123 media_entry = Column(
124 Integer, ForeignKey(MediaEntry.id),
125 nullable=False, primary_key=True)
126 name = Column(Unicode, primary_key=True)
127 file_path = Column(PathTupleWithSlashes)
128
129 def __repr__(self):
130 return "<MediaFile %s: %r>" % (self.name, self.file_path)
131
132
133 class Tag(Base):
134 __tablename__ = "tags"
135
136 id = Column(Integer, primary_key=True)
137 slug = Column(Unicode, nullable=False, unique=True)
138
139
140 class MediaTag(Base):
141 __tablename__ = "media_tags"
142
143 id = Column(Integer, primary_key=True)
144 tag = Column(Integer, ForeignKey('tags.id'), nullable=False)
145 name = Column(Unicode)
146 media_entry = Column(
147 Integer, ForeignKey('media_entries.id'),
148 nullable=False)
149 # created = Column(DateTime, nullable=False, default=datetime.datetime.now)
150
151 __table_args__ = (
152 UniqueConstraint('tag', 'media_entry'),
153 {})
154
155
156 class MediaComment(Base):
157 __tablename__ = "media_comments"
158
159 id = Column(Integer, primary_key=True)
160 media_entry = Column(
161 Integer, ForeignKey('media_entries.id'), nullable=False)
162 author = Column(Integer, ForeignKey('users.id'), nullable=False)
163 created = Column(DateTime, nullable=False, default=datetime.datetime.now)
164 content = Column(UnicodeText, nullable=False)
165 content_html = Column(UnicodeText)
166
167 get_author = relationship(User)
168
169
170 def show_table_init():
171 from sqlalchemy import create_engine
172 engine = create_engine('sqlite:///:memory:', echo=True)
173
174 Base.metadata.create_all(engine)
175
176
177 if __name__ == '__main__':
178 show_table_init()