Passed
Pull Request — develop (#31)
by Bastien
01:43
created

backend.tracim_backend.lib.webdav.design   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 387
Duplicated Lines 5.68 %

Importance

Changes 0
Metric Value
wmc 27
eloc 92
dl 22
loc 387
rs 10
c 0
b 0
f 0

3 Functions

Rating   Name   Duplication   Size   Complexity  
B designPage() 0 88 5
C designThread() 0 146 9
D create_readable_date() 22 22 13

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
#coding: utf8
2
from datetime import datetime
3
4
from tracim_backend.app_models.contents import CONTENT_TYPES
5
from tracim_backend.models.data import VirtualEvent
6
from tracim_backend.models import data
7
8
# FIXME: fix temporaire ...
9
style = """
10
.title {
11
	background:#F5F5F5;
12
	padding-right:15px;
13
	padding-left:15px;
14
	padding-top:10px;
15
	border-bottom:1px solid #CCCCCC;
16
	overflow:auto;
17
} .title h1 { margin-top:0; }
18
19
.content {
20
	padding: 15px;
21
}
22
23
#left{ padding:0; }
24
25
#right {
26
	background:#F5F5F5;
27
	border-left:1px solid #CCCCCC;
28
	border-bottom: 1px solid #CCCCCC;
29
	padding-top:15px;
30
}
31
@media (max-width: 1200px) {
32
	#right {
33
		border-top:1px solid #CCCCCC;
34
		border-left: none;
35
		border-bottom: none;
36
	}
37
}
38
39
body { overflow:auto; }
40
41
.btn {
42
	text-align: left;
43
}
44
45
.table tbody tr .my-align {
46
	vertical-align:middle;
47
}
48
49
.title-icon {
50
	font-size:2.5em;
51
	float:left;
52
	margin-right:10px;
53
}
54
.title.page, .title-icon.page { color:#00CC00; }
55
.title.thread, .title-icon.thread { color:#428BCA; }
56
57
/* ****************************** */
58
.description-icon {
59
	color:#999;
60
	font-size:3em;
61
}
62
63
.description {
64
	border-left: 5px solid #999;
65
	padding-left: 10px;
66
	margin-left: 10px;
67
	margin-bottom:10px;
68
}
69
70
.description-text {
71
	display:block;
72
	overflow:hidden;
73
	color:#999;
74
}
75
76
.comment-row:nth-child(2n) {
77
	background-color:#F5F5F5;
78
}
79
80
.comment-row:nth-child(2n+1) {
81
	background-color:#FFF;
82
}
83
84
.comment-icon {
85
	color:#CCC;
86
	font-size:3em;
87
	display:inline-block;
88
	margin-right: 10px;
89
	float:left;
90
}
91
92
.comment-content {
93
	display:block;
94
	overflow:hidden;
95
}
96
97
.comment, .comment-revision {
98
	padding:10px;
99
	border-top: 1px solid #999;
100
}
101
102
.comment-revision-icon {
103
	color:#777;
104
	margin-right: 10px;
105
}
106
107
.title-text {
108
	display: inline-block;
109
}
110
"""
111
112
_LABELS = {
113
    'archiving': 'Item archived',
114
    'content-comment': 'Item commented',
115
    'creation': 'Item created',
116
    'deletion': 'Item deleted',
117
    'edition': 'item modified',
118
    'revision': 'New revision',
119
    'status-update': 'New status',
120
    'unarchiving': 'Item unarchived',
121
    'undeletion': 'Item undeleted',
122
    'move': 'Item moved',
123
    'comment': 'Comment',
124
    'copy' : 'Item copied',
125
}
126
127
128 View Code Duplication
def create_readable_date(created, delta_from_datetime: datetime = None):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
129
    if not delta_from_datetime:
130
        delta_from_datetime = datetime.now()
131
132
    delta = delta_from_datetime - created
133
134
    if delta.days > 0:
135
        if delta.days >= 365:
136
            aff = '%d year%s ago' % (delta.days / 365, 's' if delta.days / 365 >= 2 else '')
137
        elif delta.days >= 30:
138
            aff = '%d month%s ago' % (delta.days / 30, 's' if delta.days / 30 >= 2 else '')
139
        else:
140
            aff = '%d day%s ago' % (delta.days, 's' if delta.days >= 2 else '')
141
    else:
142
        if delta.seconds < 60:
143
            aff = '%d second%s ago' % (delta.seconds, 's' if delta.seconds > 1 else '')
144
        elif delta.seconds / 60 < 60:
145
            aff = '%d minute%s ago' % (delta.seconds / 60, 's' if delta.seconds / 60 >= 2 else '')
146
        else:
147
            aff = '%d hour%s ago' % (delta.seconds / 3600, 's' if delta.seconds / 3600 >= 2 else '')
148
149
    return aff
150
151
def designPage(content: data.Content, content_revision: data.ContentRevisionRO) -> str:
152
    hist = content.get_history(drop_empty_revision=False)
153
    histHTML = '<table class="table table-striped table-hover">'
154
    for event in hist:
155
        if isinstance(event, VirtualEvent):
156
            date = event.create_readable_date()
157
            label = _LABELS[event.type.id]
158
159
            histHTML += '''
160
                <tr class="%s">
161
                    <td class="my-align"><span class="label label-default"><i class="fa %s"></i> %s</span></td>
162
                    <td>%s</td>
163
                    <td>%s</td>
164
                    <td>%s</td>
165
                </tr>
166
                ''' % ('warning' if event.id == content_revision.revision_id else '',
167
                       event.type.fa_icon,
168
                       label,
169
                       date,
170
                       event.owner.display_name,
171
                       # NOTE: (WABDAV_HIST_DEL_DISABLED) Disabled for beta 1.0
172
                       '<i class="fa fa-caret-left"></i> shown'  if event.id == content_revision.revision_id else '' # '''<span><a class="revision-link" href="/.history/%s/(%s - %s) %s.html">(View revision)</a></span>''' % (
173
                       # content.label, event.id, event.type.id, event.ref_object.label) if event.type.id in ['revision', 'creation', 'edition'] else '')
174
                   )
175
    histHTML += '</table>'
176
177
    page = '''
178
<html>
179
<head>
180
	<meta charset="utf-8" />
181
	<title>%s</title>
182
	<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
183
	<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css">
184
	<style>%s</style>
185
	<script type="text/javascript" src="/home/arnaud/Documents/css/script.js"></script>
186
	<script
187
			  src="https://code.jquery.com/jquery-3.1.0.min.js"
188
			  integrity="sha256-cCueBR6CsyA4/9szpPfrX3s49M9vUU5BgtiJj06wt/s="
189
			  crossorigin="anonymous"></script>
190
</head>
191
<body>
192
    <div id="left" class="col-lg-8 col-md-12 col-sm-12 col-xs-12">
193
        <div class="title page">
194
            <div class="title-text">
195
                <i class="fa fa-file-text-o title-icon page"></i>
196
                <h1>%s</h1>
197
                <h6>page created on <b>%s</b> by <b>%s</b></h6>
198
            </div>
199
            <div class="pull-right">
200
                <div class="btn-group btn-group-vertical">
201
                    <!-- NOTE: Not omplemented yet, don't display not working link
202
                     <a class="btn btn-default">
203
                         <i class="fa fa-external-link"></i> View in tracim</a>
204
                     </a>-->
205
                </div>
206
            </div>
207
        </div>
208
        <div class="content col-xs-12 col-sm-12 col-md-12 col-lg-12">
209
            %s
210
        </div>
211
    </div>
212
    <div id="right" class="col-lg-4 col-md-12 col-sm-12 col-xs-12">
213
        <h4>History</h4>
214
        %s
215
    </div>
216
    <script type="text/javascript">
217
        window.onload = function() {
218
            file_location = window.location.href
219
            file_location = file_location.replace(/\/[^/]*$/, '')
220
            file_location = file_location.replace(/\/.history\/[^/]*$/, '')
221
222
            // NOTE: (WABDAV_HIST_DEL_DISABLED) Disabled for beta 1.0
223
            // $('.revision-link').each(function() {
224
            //    $(this).attr('href', file_location + $(this).attr('href'))
225
            // });
226
        }
227
    </script>
228
</body>
229
</html>
230
        ''' % (content_revision.label,
231
               style,
232
               content_revision.label,
233
               content.created.strftime("%B %d, %Y at %H:%m"),
234
               content.owner.display_name,
235
               content_revision.description,
236
               histHTML)
237
238
    return page
239
240
241
def designThread(content: data.Content, content_revision: data.ContentRevisionRO, comments) -> str:
242
        hist = content.get_history(drop_empty_revision=False)
243
244
        allT = []
245
        allT += comments
246
        allT += hist
247
        allT.sort(key=lambda x: x.created, reverse=True)
248
249
        disc = ''
250
        participants = {}
251
        for t in allT:
252
            if t.type == CONTENT_TYPES.Comment.slug:
253
                disc += '''
254
                    <div class="row comment comment-row">
255
                        <i class="fa fa-comment-o comment-icon"></i>
256
                            <div class="comment-content">
257
                            <h5>
258
                                <span class="comment-author"><b>%s</b> wrote :</span>
259
                                <div class="pull-right text-right">%s</div>
260
                            </h5>
261
                            %s
262
                        </div>
263
                    </div>
264
                    ''' % (t.owner.display_name, create_readable_date(t.created), t.description)
265
266
                if t.owner.display_name not in participants:
267
                    participants[t.owner.display_name] = [1, t.created]
268
                else:
269
                    participants[t.owner.display_name][0] += 1
270
            else:
271
                if isinstance(t, VirtualEvent) and t.type.id != 'comment':
272
                    label = _LABELS[t.type.id]
273
274
                    disc += '''
275
                    <div class="%s row comment comment-row to-hide">
276
                        <i class="fa %s comment-icon"></i>
277
                            <div class="comment-content">
278
                            <h5>
279
                                <span class="comment-author"><b>%s</b></span>
280
                                <div class="pull-right text-right">%s</div>
281
                            </h5>
282
                            %s %s
283
                        </div>
284
                    </div>
285
                    ''' % ('warning' if t.id == content_revision.revision_id else '',
286
                           t.type.fa_icon,
287
                           t.owner.display_name,
288
                           t.create_readable_date(),
289
                           label,
290
                            # NOTE: (WABDAV_HIST_DEL_DISABLED) Disabled for beta 1.0
291
                            '<i class="fa fa-caret-left"></i> shown' if t.id == content_revision.revision_id else '' # else '''<span><a class="revision-link" href="/.history/%s/%s-%s">(View revision)</a></span>''' % (
292
                               # content.label,
293
                               # t.id,
294
                               # t.ref_object.label) if t.type.id in ['revision', 'creation', 'edition'] else '')
295
                           )
296
297
        thread = '''
298
<html>
299
<head>
300
	<meta charset="utf-8" />
301
	<title>%s</title>
302
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
303
	<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
304
	<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css">
305
	<style>%s</style>
306
	<script type="text/javascript" src="/home/arnaud/Documents/css/script.js"></script>
307
</head>
308
<body>
309
    <div id="left" class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
310
        <div class="title thread">
311
            <div class="title-text">
312
                <i class="fa fa-comments-o title-icon thread"></i>
313
                <h1>%s</h1>
314
                <h6>thread created on <b>%s</b> by <b>%s</b></h6>
315
            </div>
316
            <div class="pull-right">
317
                <div class="btn-group btn-group-vertical">
318
                    <!-- NOTE: Not omplemented yet, don't display not working link
319
                    <a class="btn btn-default" onclick="hide_elements()">
320
                       <i id="hideshow" class="fa fa-eye-slash"></i> <span id="hideshowtxt" >Hide history</span></a>
321
                    </a>-->
322
                    <a class="btn btn-default">
323
                        <i class="fa fa-external-link"></i> View in tracim</a>
324
                    </a>
325
                </div>
326
            </div>
327
        </div>
328
        <div class="content col-xs-12 col-sm-12 col-md-12 col-lg-12">
329
            <div class="description">
330
                <span class="description-text">%s</span>
331
            </div>
332
            %s
333
        </div>
334
    </div>
335
    <script type="text/javascript">
336
        window.onload = function() {
337
            file_location = window.location.href
338
            file_location = file_location.replace(/\/[^/]*$/, '')
339
            file_location = file_location.replace(/\/.history\/[^/]*$/, '')
340
341
            // NOTE: (WABDAV_HIST_DEL_DISABLED) Disabled for beta 1.0
342
            // $('.revision-link').each(function() {
343
            //     $(this).attr('href', file_location + $(this).attr('href'))
344
            // });
345
        }
346
347
        function hide_elements() {
348
            elems = document.getElementsByClassName('to-hide');
349
            if (elems.length > 0) {
350
                for(var i = 0; i < elems.length; i++) {
351
                    $(elems[i]).addClass('to-show')
352
                    $(elems[i]).hide();
353
                }
354
                while (elems.length>0) {
355
                    $(elems[0]).removeClass('comment-row');
356
                    $(elems[0]).removeClass('to-hide');
357
                }
358
                $('#hideshow').addClass('fa-eye').removeClass('fa-eye-slash');
359
                $('#hideshowtxt').html('Show history');
360
            }
361
            else {
362
                elems = document.getElementsByClassName('to-show');
363
                for(var i = 0; i<elems.length; i++) {
364
                    $(elems[0]).addClass('comment-row');
365
                    $(elems[i]).addClass('to-hide');
366
                    $(elems[i]).show();
367
                }
368
                while (elems.length>0) {
369
                    $(elems[0]).removeClass('to-show');
370
                }
371
                $('#hideshow').removeClass('fa-eye').addClass('fa-eye-slash');
372
                $('#hideshowtxt').html('Hide history');
373
            }
374
        }
375
    </script>
376
</body>
377
</html>
378
        ''' % (content_revision.label,
379
               style,
380
               content_revision.label,
381
               content.created.strftime("%B %d, %Y at %H:%m"),
382
               content.owner.display_name,
383
               content_revision.description,
384
               disc)
385
386
        return thread
387