1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
|
skinparam linetype ortho
namespace django #DDDDDD {
namespace django.db.models {
class FileField {}
class FieldFile {}
class FileDescriptor {}
}
namespace django.views {
class View <<V, lightblue>>{
dispatch(): HttpResponse
}
}
namespace django.forms {
class Form <<F, lightgreen >>
class ModelForm <<F, lightgreen>>
ModelForm -|> Form
}
namespace django.core.management.base {
class BaseCommand
}
namespace django.contrib.auth.base_user {
class AbstractBaseUser << (M,orchid) >>
}
'django.contrib.auth.base_user.AbstractBaseUser -d-|>django.db.models.Model
}
namespace django-media-fields.models {
AudioField -|> django.db.models.FileField
class AudioField {
length_field: str
update_metadata_fields(self, instance, force=False, *args, **kwargs)
}
AudioFileDescriptor -|> django.db.models.FileDescriptor
AudioFieldFile -|> django.db.models.FieldFile
AudioField -[hidden]d- AudioFileDescriptor
AudioFileDescriptor -[hidden]d- AudioFieldFile
AudioFieldFile -[hidden]d- VideoField
VideoField -|> django.db.models.FileField
class VideoField {
length_field: str
width_field: str
height_field: str
update_metadata_fields(self, instance, force=False, *args, **kwargs)
}
VideoFileDescriptor -|> django.db.models.FileDescriptor
VideoFieldFile -d-|> django.db.models.FieldFile
VideoField -[hidden]d- VideoFileDescriptor
VideoFileDescriptor -[hidden]d- VideoFieldFile
}
namespace dill {
namespace dill.accounts {
namespace dill.accounts.backends {
class BaseBackend {
authenticate(request: Request, **kwargs);
get_user(user_id: int): User
}
HttpUserBackend -d-|> BaseBackend
class HttpUserBackend {
authenticate(request: Request, **kwargs): User
}
LDAPBackend -d-|> BaseBackend
class LDAPBackend {
authenticate(request: Request, username: str, password: str, **kwargs): User
}
ShibbolethBackend -r-|> BaseBackend
class ShibbolethBackend {
authenticate(request: Request, **kwargs): User
}
}
namespace dill.accounts.mixins {
class AccessMixin {
login_url: str
redirect_field_name: str
permission_denied_message: str
dispatch(request: Request, *args, **kwargs): Response
check_permission(user: User): bool
handle_no_permission(): Response
handle_unauthenticated(): Response
get_permission_denied_message(): str
}
LoginRequiredMixin -|> AccessMixin
class LoginRequiredMixin {
check_permission(user: User): bool
}
PermissionRequiredMixin -|> AccessMixin
class PermissionRequiredMixin {
required_permission: [Perm]
check_permission(user: User): bool
}
}
namespace dill.accounts.models {
class PermissionMixin {
get_implicit_groups(): [Group]
get_explicit_groups(): [Group]
get_groups(): [Group]
get_all_permissions(): set<Perm>
has_perms(perms: [Perm]): bool
}
User -|> django.contrib.auth.base_user.AbstractBaseUser
User .|> PermissionMixin
class User << (M, orchid) >> {
username: CharField
first_name: CharField
last_name: CharField
mail: EmailField
profile_image: ImageField
clean()
get_full_name(): str
get_short_name(): str
get_implicit_groups(): [Group]
<< deprecated >> is_anonymous(): bool
is_authenticated(): bool
}
User *- "many" UserGroup: groups
' AnonymousUser is not a model do not mark it as such
AnonymousUser -|> User
'UserGroup -|> django.db.models.Model
class UserGroup << (M,orchid) >> {
name: CharField
}
}
namespace dill.accounts.permissions {
class Perm {
app: str
key: str
description: str
__init__(app: str, key: str, description: str)
}
}
namespace dill.accounts.management.commands {
namespace dill.accounts.management.commands.createuser {
Command -|> django.core.management.base.BaseCommand
class Command {
add_argument(parser: OptionParser)
handle(*args, **kwargs)
}
}
namespace dill.accounts.management.commands.promoteuser {
Command -|> django.core.management.base.BaseCommand
class Command {
add_argument(parser: OptionParser)
handle(*args, **kwargs)
}
}
}
namespace dill.accounts.views {
class LoginView << (V,lightblue) >>
'LoginView -|> django.views.View
class LogoutView << (V,lightblue) >>
'LogoutView -|> django.views.View
class ProfileView << (V,lightblue) >>
'ProfileView -|> django.views.View
ProfileView .|> dill.accounts.mixins.LoginRequiredMixin
class ProfileEditView << (V,lightblue) >>
dill.accounts.mixins.PermissionRequiredMixin <|- dill.accounts.views.ProfileEditView
}
namespace dill.accounts.forms {
class AuthenticationForm <<F, lightgreen>>
AuthenticationForm o-- dill.accounts.views.LoginView
class ProfileForm <<F, lightgreen>>
ProfileForm -|> django.forms.ModelForm
ProfileForm o-- dill.accounts.views.ProfileEditView
}
namespace dill.accounts.middleware {
class AuthenticationMiddleware {
- cached_user: User
__init__(get_response: callable)
__call__(request: Request): Request
get_user(request: Request): User
}
}
namespace dill.accounts.templatetags.perms {
class PermWrapper {
__init__(user: User)
__iter__(): iterator<Perm>
__contains__(perm: Perm): bool
}
}
}
namespace dill.models {
'subpackage?
'Experiment -|> django.db.models.Model
class Experiment << (M,orchid) >> {
name: CharField
description: TextField
archived_at: DateTimeField
created_at: DateTimeField
__str__()
}
Experiment -> dill.accounts.models.User: creator
Experiment "many" <- dill.accounts.models.User: favorites
'Tag -|> django.db.models.Model
class Tag << (M,orchid) >> {
name: CharField
color: IntegerField
__str__()
}
Tag --* Experiment
class "//NoteMedia//" as NoteMedia << (M,orchid) >> {
name: CharField
content_type: CharField
size: IntegerField
thumb: ImageField
thumb_height: IntegerField
thumb_width: IntegerField
save()
}
class Note << (M,orchid) >> {
content: TextField
created_at: DateTimeField
__str__()
}
AudioMedia -|> NoteMedia
class AudioMedia << (M,orchid) >> {
file: django_file_fields.models.AudioField
length: IntegerField
__str__()
}
ImageMedia -|> NoteMedia
class ImageMedia << (M,orchid) >> {
file: ImageField
height: IntegerField
width: IntegerField
__str__()
}
VideoMedia -|> NoteMedia
class VideoMedia << (M,orchid) >> {
file: djang_file_fields.models.VideoField
length: IntegerField
height: IntegerField
width: IntegerField
}
NoteMedia -[hidden]d- Note
NoteMedia -[hidden]d- AudioMedia
AudioMedia -[hidden]d- VideoMedia
VideoMedia -[hidden]d- ImageMedia
Note -d---> dill.accounts.models.User: creator
Note -> "many" Tag: tags
Note *- "many" NoteMedia: media
Note -* Experiment: experiment
}
namespace dill.views {
'subpackage?
class ExperimentView << (V,lightblue) >>
'TODO change to ExperimentDetailView?
dill.accounts.mixins.PermissionRequiredMixin <|- dill.views.ExperimentView
'ExperimentView -|> django.views.View
class ExperimentEditView << (V,lightblue) >>
'ExperimentEditView -|> django.views.View
class Startpage << (V,lightblue) >>
class SearchResultPage << (V, lightblue) >>
}
namespace dill.forms {
'subpackage?
class ExperimentForm <<F, lightgreen>>
ExperimentForm -|> django.forms.ModelForm
ExperimentForm o-- dill.views.ExperimentEditView
class NoteForm <<F, lightgreen>>
NoteForm o-- dill.views.ExperimentView
}
namespace dill.admin {
namespace dill.admin.views {
class ExportView << (V,lightblue) >>
class UserListView << (V,lightblue) >>
'ExportView -|> django.views.View
dill.admin.views.ExportView -|> dill.accounts.mixins.PermissionRequiredMixin
dill.accounts.mixins.PermissionRequiredMixin <|- dill.admin.views.UserListView
}
}
'django-media-fields.models.VideoField -[hidden]d- django.contrib.auth.base_user.AbstractBaseUser
' make it nice
django.contrib.auth.base_user.AbstractBaseUser -[hidden]d- django.core.management.base.BaseCommand
'django.forms -[hidden]u- django.db.models
django.core.management.base.BaseCommand -[hidden]d- django.forms
'django.views -[hidden]u- django.forms
dill.accounts.middleware -[hidden]d- dill.admin
'django.forms -[hidden]d- django.core.management.base.BaseCommand
'django.core.management.base.BaseCommand -[hidden]d- django.views
dill.models --[hidden]d- dill.accounts
dill.accounts.mixins.LoginRequiredMixin --[hidden]l- dill.accounts.mixins.AccessMixin
dill.accounts.models -[hidden]d- dill.accounts.management.commands
dill.accounts.management.commands -[hidden]l- dill.accounts.permissions
dill.accounts.permissions --[hidden]d- dill.accounts.backends
dill.accounts.backends --[hidden]d- dill.accounts.forms
dill.accounts.views -[hidden]d- dill.accounts.mixins
'dill.accounts.views -[hidden]d- dill.accounts.forms
dill.accounts.mixins --[hidden]d- dill.accounts.middleware
dill.accounts.middleware -[hidden]l- dill.accounts.templatetags.perms
}
|