Test suite runs and passes!
[zzz-floof.git] / floof / model / users.py
1 #
2 # floof/floof/model/users.py
3 #
4 # Copyright (c) 2009 Scribblr
5 #
6
7 import re
8
9 from elixir import *
10
11 from search import GalleryWidget
12
13 class User(Entity):
14 name = Field(Unicode(20), unique=True, required=True)
15 display_name = Field(Unicode(20), required=True)
16 uploads = OneToMany('Art')
17 has_many('identity_urls', of_kind='IdentityURL')
18 searches = OneToMany('SavedSearch')
19 # galleries = OneToMany('GalleryWidget')
20 pages = OneToMany('UserPage', inverse="owner")
21 primary_page = OneToOne('UserPage', inverse="owner")
22 relationships = OneToMany('UserRelationship', inverse='user')
23 target_of_relationships = OneToMany('UserRelationship', inverse='target_user')
24
25 @classmethod
26 def is_valid_name(cls, name):
27 """Returns True iff the name is a valid username.
28
29 Only lowercase letters, numbers, and hyphens are allowed.
30
31 Names must also be at least one character long, but no more than 20,
32 and cannot start or end with a hyphen.
33 """
34 return re.match('^[-a-z0-9]{1,20}$', name) \
35 and name[0] != '-' and name[-1] != '-'
36
37
38 def __unicode__(self):
39 return self.name
40
41 def __str__(self):
42 return self.name
43
44 def __init__(self, **kwargs):
45 super(User, self).__init__(**kwargs)
46
47
48
49 # TODO: have this clone a standard starter page
50 self.primary_page = UserPage(owner=self, title="default", visible=True)
51 prepositions = ['by','for','of']
52 for preposition in prepositions:
53 GalleryWidget(page=self.primary_page, string=preposition+":me", owner=self)
54
55 #UserPage.clone_primary_template(self)
56
57
58 class IdentityURL(Entity):
59 url = Field(Unicode(255), required=True)
60 user = ManyToOne('User', required=True)
61
62
63 from copy import copy
64 class UserPage(Entity):
65 default_name = "default"
66
67 ### This was a bit more complex than I thought it would be...
68 ### Sure it probably works ok, but I'd rather duct-tape it for now (above)
69 # @classmethod
70 # def get_primary_template(cls):
71 # return cls.get_by(owner=None, title=cls.default_name)
72 #
73 # @classmethod
74 # def make_primary_template(cls):
75 # if not cls.get_primary_template():
76 # page = cls(owner=None, title=cls.default_name, visible=True)
77 # prepositions = ['by','for','of']
78 # for preposition in prepositions:
79 # GalleryWidget(page=page, string=preposition+":me")
80 #
81 # @classmethod
82 # def clone_primary_template(cls, user):
83 # template = cls.get_primary_template()
84 # new = cls(owner=user, title=template.title)
85 # for gallery in template.galleries:
86 # new.galleries.append(GalleryWidget(user=user, string=gallery.string))
87 #
88 #
89 # session.add(template)
90 # template.user = user
91 # template.id = None
92 # return template
93
94 """A user can have multiple pages, though by default they only have one visible.
95 This is so that they can keep some nice themed pages lying around for special occasions.
96 Page templates that provide familiar interfaces will also be UserPage records. Users will
97 see a panel full of them, and they can choose to clone those template pages to their own page list.
98 If more than one is set to visible, there would be tabs. The primary page is indicated in the user model.
99 """
100
101 owner = ManyToOne('User', inverse="pages")
102 title = Field(String)
103
104 visible = Field(Boolean)
105 galleries = OneToMany('GalleryWidget')
106
107
108 class UserRelationshipTypes(object):
109 IS_WATCHING = 1
110
111 class UserRelationship(Entity):
112 """Represents some sort of connection between users.
113
114 For the moment, this means "watching". Later, it may mean friending or
115 ignoring.
116
117 XXX: Watching should be made more general than this; it should have the
118 power of an arbitrary query per watched artist without being unintelligible
119 to users.
120 """
121
122 user = ManyToOne('User', required=True)
123 target_user = ManyToOne('User', required=True)
124 type = Field(Integer) # UserRelationshipTypes above
125