Completed
Pull Request — master (#51)
by Michal
58s
created

Download.is_featured()   A

Complexity

Conditions 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
c 0
b 0
f 0
cc 1
rs 10
1
# -*- coding: UTF-8 -*-
2
# vim: set expandtab sw=4 ts=4 sts=4:
3
#
4
# phpMyAdmin web site
5
#
6
# Copyright (C) 2008 - 2016 Michal Cihar <[email protected]>
7
#
8
# This program is free software; you can redistribute it and/or modify
9
# it under the terms of the GNU General Public License as published by
10
# the Free Software Foundation; either version 2 of the License, or
11
# (at your option) any later version.
12
#
13
# This program is distributed in the hope that it will be useful,
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
# GNU General Public License for more details.
17
#
18
# You should have received a copy of the GNU General Public License along
19
# with this program; if not, write to the Free Software Foundation, Inc.,
20
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
22
import urllib2
23
from django.dispatch import receiver
24
from django.db.models.signals import post_save
25
from django.core.urlresolvers import reverse
26
from django.db import models
27
from django.conf import settings
28
from django.utils import timezone
29
import os.path
30
from data.themes import CSSMAP
31
from markupfield.fields import MarkupField
32
from pmaweb.cdn import purge_cdn, purge_all_cdn
33
34
# Naming of versions
35
VERSION_INFO = (
36
    ('alpha1', ' First alpha version.'),
37
    ('alpha2', ' Second alpha version.'),
38
    ('alpha3', ' Third alpha version.'),
39
    ('alpha4', ' Fourth alpha version.'),
40
    ('beta1', ' First beta version.'),
41
    ('beta2', ' Second beta version.'),
42
    ('beta3', ' Third beta version.'),
43
    ('beta4', ' Fourth beta version.'),
44
    ('beta', ' Beta version.'),
45
    ('rc1', ' First release candidate.'),
46
    ('rc2', ' Second release candidate.'),
47
    ('rc3', ' Third release candidate.'),
48
    ('rc4', ' Fourth release candidate.'),
49
    ('rc', ' Release candidate.'),
50
)
51
52
DOCKER_TRIGGER = \
53
    'https://registry.hub.docker.com/u/phpmyadmin/phpmyadmin/trigger/{0}/'
54
55
56
def get_current_releases():
57
    delta = 1000000
58
    result = []
59
60
    for version in settings.LISTED_BRANCHES:
61
        min_vernum = Release.parse_version(version)
62
        max_vernum = min_vernum + delta
63
        stable_releases = Release.objects.filter(
64
            version_num__gte=min_vernum,
65
            version_num__lt=max_vernum,
66
            stable=True,
67
        )
68
        if stable_releases.exists():
69
            result.append(stable_releases[0])
70
71
    return result
72
73
74
class Release(models.Model):
75
    version = models.CharField(max_length=50, unique=True)
76
    version_num = models.IntegerField(default=0, unique=True)
77
    release_notes = MarkupField(default_markup_type='markdown')
78
    stable = models.BooleanField(default=False, db_index=True)
79
    date = models.DateTimeField(db_index=True, default=timezone.now)
80
81
    class Meta(object):
82
        ordering = ['-version_num']
83
84
    def __unicode__(self):
85
        return self.version
86
87
    @models.permalink
88
    def get_absolute_url(self):
89
        return ('release', (), {'version': self.version})
90
91
    def simpledownload(self):
92
        try:
93
            return self.download_set.get(
94
                filename__endswith='-all-languages.zip'
95
            )
96
        except Download.DoesNotExist:
97
            try:
98
                return self.download_set.all()[0]
99
            except IndexError:
100
                return None
101
102
    @staticmethod
103
    def parse_version(version):
104
        if '-' in version:
105
            version, suffix = version.split('-')
106
            if suffix.startswith('alpha'):
107
                suffix_num = int(suffix[5:])
108
            elif suffix.startswith('beta'):
109
                suffix_num = 10 + int(suffix[4:])
110
            elif suffix.startswith('rc'):
111
                suffix_num = 50 + int(suffix[2:])
112
            else:
113
                raise ValueError(version)
114
        else:
115
            suffix_num = 99
116
            version = version
117
        parts = [int(x) for x in version.split('.')]
118
        if len(parts) == 2:
119
            parts.append(0)
120
        if len(parts) == 3:
121
            parts.append(0)
122
        assert len(parts) == 4
123
        return (
124
            100000000 * parts[0] +
125
            1000000 * parts[1] +
126
            10000 * parts[2] +
127
            100 * parts[3] +
128
            suffix_num
129
        )
130
131
    def save(self, *args, **kwargs):
132
        self.version_num = self.parse_version(self.version)
133
        self.stable = self.version_num % 100 == 99
134
        super(Release, self).save(*args, **kwargs)
135
136
    def get_version_suffix(self):
137
        '''
138
        Returns suffix for a version.
139
        '''
140
        for match, result in VERSION_INFO:
141
            if self.version.find(match) != -1:
142
                return result
143
        return ''
144
145
    def get_php_versions(self):
146
        if self.version[:3] == '4.6':
147
            return '>=5.5,<7.1'
148
        elif self.version[:3] == '4.5':
149
            return '>=5.5,<7.1'
150
        elif self.version[:3] == '4.4':
151
            return '>=5.3,<7.1'
152
        elif self.version[:3] == '4.3':
153
            return '>=5.3,<7.0'
154
        elif self.version[:3] == '4.2':
155
            return '>=5.3,<7.0'
156
        elif self.version[:3] == '4.1':
157
            return '>=5.3,<7.0'
158
        elif self.version[:3] == '4.0':
159
            return '>=5.2,<5.3'
160
161
    def get_mysql_versions(self):
162
        if self.version[:3] == '4.6':
163
            return '>=5.5'
164
        elif self.version[:3] == '4.5':
165
            return '>=5.5'
166
        elif self.version[:3] == '4.4':
167
            return '>=5.5'
168
        elif self.version[:3] == '4.3':
169
            return '>=5.5'
170
        elif self.version[:3] == '4.2':
171
            return '>=5.5'
172
        elif self.version[:3] == '4.1':
173
            return '>=5.5'
174
        elif self.version[:3] == '4.0':
175
            return '>=5.0'
176
177
    def get_version_info(self):
178
        '''
179
        Returns description to the phpMyAdmin version.
180
        '''
181
        if self.version[:2] == '0.':
182
            text = 'Historical release.'
183
        elif self.version[:2] == '1.':
184
            text = 'Historical release.'
185
        elif self.version[:2] == '2.':
186
            text = 'Version compatible with PHP 4+ and MySQL 3+.'
187
        elif self.version[:2] == '3.':
188
            text = (
189
                'Frames version not requiring Javascript. ' +
190
                'Requires PHP 5.2 and MySQL 5. ' +
191
                'Supported for security fixes only, until Jan 1, 2014.'
192
            )
193
        elif self.version[:3] == '4.6':
194
            text = (
195
                'Current version compatible with PHP 5.5 to 7.0 and MySQL 5.5 and newer. '
196
            )
197
        elif self.version[:3] == '4.5':
198
            text = (
199
                'Current version compatible with PHP 5.5 to 7.0 and MySQL 5.5. ' +
200
                'Supported until April 1, 2016.'
201
            )
202
        elif self.version[:3] == '4.4':
203
            text = (
204
                'Older version compatible with PHP 5.3.7 to 7.0 and MySQL 5.5. ' +
205
                'Supported for security fixes only, until October 1, 2016.'
206
            )
207
        elif self.version[:3] == '4.3':
208
            text = (
209
                'Older version compatible with PHP 5.3 and MySQL 5.5. ' +
210
                'Supported for security fixes only, until October 1, 2015.'
211
            )
212
        elif self.version[:3] == '4.2':
213
            text = (
214
                'Older version compatible with PHP 5.3 and MySQL 5.5. ' +
215
                'Supported for security fixes only, until July 1, 2015.'
216
            )
217
        elif self.version[:3] == '4.1':
218
            text = (
219
                'Older version compatible with PHP 5.3 and MySQL 5.5. ' +
220
                'Supported for security fixes only, until January 1, 2015.'
221
            )
222
        elif self.version[:3] == '4.0':
223
            text = (
224
                'Older version compatible with PHP 5.2 and MySQL 5. ' +
225
                'Supported for security fixes only, until April 1, 2017.'
226
            )
227
        text += self.get_version_suffix()
228
229
        return text
230
231
    def get_downloads(self):
232
        """Lists downloads, making all-languages.zip first"""
233
        dlset = self.download_set
234
        return (
235
            list(dlset.filter(filename__endswith='all-languages.zip')) +
236
            list(dlset.exclude(filename__endswith='all-languages.zip'))
237
        )
238
239
240
class Download(models.Model):
241
    release = models.ForeignKey(Release)
242
    filename = models.CharField(max_length=50)
243
    size = models.IntegerField(default=0)
244
    sha1 = models.CharField(max_length=40)
245
    sha256 = models.CharField(max_length=64)
246
    signed = models.BooleanField(default=False)
247
248
    class Meta(object):
249
        ordering = ['-release__version_num', 'filename']
250
        unique_together = ['release', 'filename']
251
252
    def __unicode__(self):
253
        return '/phpMyAdmin/{0}/{1}'.format(
254
            self.release.version,
255
            self.filename
256
        )
257
258
    @property
259
    def size_k(self):
260
        return self.size / 1024
261
262
    @property
263
    def size_m(self):
264
        return self.size / (1024 * 1024)
265
266
    def get_filesystem_path(self):
267
        return os.path.join(
268
            settings.FILES_PATH,
269
            'phpMyAdmin',
270
            self.release.version,
271
            self.filename
272
        )
273
274
    def get_absolute_url(self):
275
        return 'https://files.phpmyadmin.net{0}'.format(
276
            self.__unicode__()
277
        )
278
279
    def get_signed_url(self):
280
        if not self.signed:
281
            return ''
282
        return 'https://files.phpmyadmin.net{0}.asc'.format(
283
            self.__unicode__()
284
        )
285
286
    def get_alternate_url(self):
287
        return 'https://1126968067.rsc.cdn77.org{0}'.format(
288
            self.__unicode__()
289
        )
290
291
    @property
292
    def archive(self):
293
        return self.filename.rsplit('.', 1)[-1]
294
295
    @property
296
    def composer_type(self):
297
        ext = self.filename.rsplit('.', 1)[-1]
298
        if ext == 'zip':
299
            return 'zip'
300
        else:
301
            return 'tar'
302
303
    @property
304
    def is_featured(self):
305
        return self.filename.endswith('all-languages.zip')
306
307
308
class Theme(models.Model):
309
    name = models.CharField(max_length=50)
310
    display_name = models.CharField(max_length=50)
311
    version = models.CharField(max_length=50)
312
    filename = models.CharField(max_length=100, unique=True)
313
    supported_versions = models.CharField(max_length=50)
314
    description = models.TextField()
315
    author = models.CharField(max_length=200)
316
    size = models.IntegerField(default=0)
317
    sha1 = models.CharField(max_length=40)
318
    sha256 = models.CharField(max_length=64)
319
    signed = models.BooleanField(default=False)
320
    date = models.DateTimeField(db_index=True, default=timezone.now)
321
322
    class Meta(object):
323
        ordering = ['name', 'version']
324
325
    def __unicode__(self):
326
        return u'{0} {1}'.format(self.display_name, self.version)
327
328
    @property
329
    def imgname(self):
330
        return 'images/themes/{0}.png'.format(self.name)
331
332
    def get_absolute_url(self):
333
        return 'https://files.phpmyadmin.net/themes/{0}/{1}/{2}'.format(
334
            self.name,
335
            self.version,
336
            self.filename,
337
        )
338
339
    def get_signed_url(self):
340
        if not self.signed:
341
            return ''
342
        return 'https://files.phpmyadmin.net/themes/{0}/{1}/{2}.asc'.format(
343
            self.name,
344
            self.version,
345
            self.filename,
346
        )
347
348
    def get_filesystem_path(self):
349
        return os.path.join(
350
            settings.FILES_PATH,
351
            'themes',
352
            self.name,
353
            self.version,
354
            self.filename
355
        )
356
357
    @property
358
    def get_css(self):
359
        return CSSMAP[self.supported_versions]
360
361
362
@receiver(post_save, sender=Release)
363
def dockerhub_trigger(sender, instance, **kwargs):
364
    if settings.DOCKERHUB_TOKEN is None:
365
        return
366
    request = urllib2.Request(
367
        DOCKER_TRIGGER.format(settings.DOCKERHUB_TOKEN),
368
        '{"build": true}',
369
        {'Content-Type': 'application/json'}
370
    )
371
    handle = urllib2.urlopen(request)
372
    handle.read()
373
374
375
@receiver(post_save, sender=Release)
376
def purge_release(sender, instance, **kwargs):
377
    purge_cdn(
378
        # Pages with _littleboxes.html
379
        reverse('home'),
380
        reverse('news'),
381
        # Download lists
382
        reverse('files'),
383
        reverse('feed-files'),
384
        reverse('downloads'),
385
        # Version dumps
386
        '/downloads/list.txt',
387
        '/home_page/version.txt',
388
        '/home_page/version.js',
389
        '/home_page/version.json',
390
        '/downloads/phpMyAdmin-latest-all-languages.tar.bz2',
391
        '/downloads/phpMyAdmin-latest-all-languages.tar.gz',
392
        '/downloads/phpMyAdmin-latest-all-languages.tar.xz',
393
        '/downloads/phpMyAdmin-latest-all-languages.zip',
394
        '/downloads/phpMyAdmin-latest-english.tar.bz2',
395
        '/downloads/phpMyAdmin-latest-english.tar.gz',
396
        '/downloads/phpMyAdmin-latest-english.tar.xz',
397
        '/downloads/phpMyAdmin-latest-english.zip',
398
        reverse('doap'),
399
        reverse('pad'),
400
        # This release
401
        instance.get_absolute_url(),
402
    )
403
    # Purge all pages as every page contains download link
404
    purge_all_cdn()
405
406
407
@receiver(post_save, sender=Download)
408
def purge_download(sender, instance, **kwargs):
409
    purge_release(sender, instance.release)
410
411
412
@receiver(post_save, sender=Theme)
413
def purge_theme(sender, instance, **kwargs):
414
    purge_cdn(reverse('themes'))
415