Revision 511913cb

b/cloudcms/admin.py
40 40
    raw_id_fields = ('logo', 'favicon')
41 41

  
42 42

  
43
class ClientVersionSourceAdminInline(admin.StackedInline):
44
    model = models.ClientVersionSource
45
    raw_id_fields = ('logo',)
46
    extra = 1
47

  
48
class ClientAdmin(admin.ModelAdmin):
49
    inlines = [ClientVersionSourceAdminInline]
50

  
51

  
43 52
admin.site.register(models.Application, ApplicationAdmin)
53
admin.site.register(models.Client, ClientAdmin)
44 54

  
b/cloudcms/clients.py
1
"""
2
CMS dynamic application clients module
3

  
4
Helper module to automatically retrieve client download links from different
5
sources (e.g. redmine files page).
6
"""
7

  
8
import urllib, urllib2, cookielib, urlparse
9

  
10
from datetime import datetime
11
from lxml import html
12

  
13
from synnefo import settings
14

  
15
CLIENTS_CACHE_TIMEOUT = getattr(settings, 'CLOUDCMS_CLIENTS_CACHE_TIMEOUT', 120)
16

  
17
class VersionSource(object):
18
    """
19
    Base class for the different version source handlers.
20
    """
21
    def __init__(self, link=None, os="linux", arch="all", regex=".", name=None,
22
            cache_backend=None, extra_options={}):
23
        self.os = os
24
        self.arch = arch
25
        self.link = link
26
        self.versions = []
27
        extra_options.update({'source_type': self.source_type, 'os': os})
28
        self.extra_version_options = extra_options
29

  
30
        self.cache_backend = cache_backend
31
        self.cache_key = self.os + self.arch + self.link
32

  
33
        if not name:
34
            self.name = os
35

  
36
        # generic urllib2 opener
37
        self.opener = urllib2.build_opener(
38
                    urllib2.HTTPRedirectHandler(),
39
                    urllib2.HTTPHandler(debuglevel=0),
40
                    urllib2.HTTPSHandler(debuglevel=0),
41
                    urllib2.HTTPCookieProcessor(cookielib.CookieJar()))
42

  
43
    def get_url(self, url):
44
        """
45
        Load url content and return the html etree object.
46
        """
47
        return html.document_fromstring(self.opener.open(url).read())
48

  
49
    def load(self):
50
        """
51
        Fill self.versions attribute with dict objects of the following format
52

  
53
        {'date': datetime.datetime(2012, 3, 16, 14, 29),
54
         'link': 'http://www.domain.com/clientdownload.exe',
55
         'name': 'Client download',
56
         'os': 'windows',
57
         'version': None}
58
        """
59
        raise NotImplemented
60

  
61
    def update(self):
62
        """
63
        Load wrapper which handles versions caching if cache_backend is set
64
        """
65
        if self.cache_backend:
66
            self.versions = self.cache_backend.get(self.cache_key)
67

  
68
        if not self.versions:
69
            self.load()
70

  
71
        if self.cache_backend:
72
            self.cache_backend.set(self.cache_key, self.versions, CLIENTS_CACHE_TIMEOUT)
73

  
74
    def get_latest(self):
75
        """
76
        Return the latest versions
77
        """
78

  
79
        # update versions
80
        self.update()
81

  
82
        # check that at least one version is available
83
        if len(self.versions):
84
            version = self.versions[0]
85
            version.update(self.extra_version_options)
86
            return version
87

  
88
        return None
89

  
90

  
91
class RedmineSource(VersionSource):
92
    """
93
    Parse a redmine project files page and return the list of existing files.
94
    """
95
    source_type = 'redmine_files'
96

  
97
    def load(self):
98
        """
99
        Load redmine files url and extract downloads. Also parse date to be
100
        able to identify latest download.
101
        """
102
        spliturl = urlparse.urlsplit(self.link)
103
        baseurl = spliturl.geturl().replace(spliturl.path, '')
104
        html = self.get_url(self.link)
105
        files = html.xpath("//tr[contains(@class, 'file')]")
106

  
107
        # helper lambdas
108
        def _parse_row(row):
109
            name = row.xpath("td[@class='filename']/a")[0].text
110
            link = baseurl + row.xpath("td[@class='filename']/a")[0].attrib.get('href')
111
            strdate = row.xpath("td[@class='created_on']")[0].text
112
            date = datetime.strptime(strdate, '%m/%d/%Y %I:%M %p')
113
            return {'name': name, 'link': link, 'date': date, 'version': None}
114

  
115
        versions = map(_parse_row, files)
116
        versions.sort(reverse=True, key=lambda r:r['date'])
117
        self.versions = versions
118
        return self
119

  
120

  
121
class DirectSource(VersionSource):
122
    """
123
    Direct link to a version. Dummy VersionSource which always returns one entry
124
    for the provided link.
125
    """
126
    source_type = 'direct'
127

  
128
    def load(self):
129
        self.versions = [{'name': self.name, 'link': self.link, 'date': None}]
130
        return self.versions
131

  
132

  
133
class LinkSource(DirectSource):
134
    """
135
    Used when version exists in some other url (e.g. apple store client)
136
    """
137
    source_type = 'link'
138

  
139

  
140
class ClientVersions(object):
141
    """
142
    Client versions manager. Given a sources dict like::
143

  
144
    {'windows': {'source_type': 'direct', 'args':
145
    ['http://clients.com/win.exe'], 'kwargs': {}},
146
     'linux': {'redmine_files': 'direct',
147
     'args': ['http://redmine.com/projects/client/files'],
148
     'kwargs': {}}}
149

  
150
    initializes a dict of proper VersionSource objects.
151
    """
152

  
153
    def __init__(self, sources, cache_backend=None):
154
        self._sources = sources
155
        self.sources = {}
156

  
157
        for s in self._sources:
158
            source_params = self._sources.get(s)
159
            if source_params['type'] in SOURCE_TYPES:
160
                kwargs = {'os': s, 'cache_backend': cache_backend}
161
                args = source_params.get('args', [])
162
                self.sources[s] = SOURCE_TYPES[source_params['type']](*args, **kwargs)
163

  
164
    def get_latest_versions(self):
165
        """
166
        Return the latest version of each version source.
167
        """
168
        for os, source in self.sources.iteritems():
169
            yield source.get_latest()
170

  
171

  
172
# SOURCE TYPES CLASS MAP
173
SOURCE_TYPES = {
174
    'redmine_files': RedmineSource,
175
    'direct': DirectSource,
176
    'link': LinkSource
177
}
178

  
b/cloudcms/cms.py
139 139
Page.create_content_type(VideoSection)
140 140
Page.create_content_type(LatestEntries)
141 141
Page.create_content_type(IntroButton)
142
Page.create_content_type(ClientDownload)
142 143
Page.create_content_type(ImageContent, POSITION_CHOICES=(
143 144
    ('default', 'Default position'),
144 145
))
b/cloudcms/content.py
196 196
        return render_to_string(['content/intro_images.html'], {'content': self})
197 197

  
198 198

  
199
class ClientDownload(models.Model):
200

  
201
    client = models.ForeignKey('cloudcms.Client')
202

  
203
    @property
204
    def media(self):
205
        return forms.Media(js=(
206
            settings.MEDIA_URL + 'cloudcms/' + 'js/' + 'client-downloads.js',))
207

  
208
    class Meta:
209
        abstract = True
210
        verbose_name = _('client download')
211
        verbose_name_plural = _('client downloads')
212

  
213
    def render(self, **kwrags):
214
        return render_to_string(['content/client_downloads.html'], {'content': self})
b/cloudcms/migrate/page/0009_auto__add_resourceslist__add_clientdownload.py
1
# encoding: utf-8
2
import datetime
3
from south.db import db
4
from south.v2 import SchemaMigration
5
from django.db import models
6

  
7
class Migration(SchemaMigration):
8

  
9
    def forwards(self, orm):
10

  
11
        # Adding model 'ClientDownload'
12
        db.create_table('page_page_clientdownload', (
13
            ('ordering', self.gf('django.db.models.fields.IntegerField')(default=0)),
14
            ('region', self.gf('django.db.models.fields.CharField')(max_length=255)),
15
            ('client', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['cloudcms.Client'])),
16
            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
17
            ('parent', self.gf('django.db.models.fields.related.ForeignKey')(related_name='clientdownload_set', to=orm['page.Page'])),
18
        ))
19
        db.send_create_signal('page', ['ClientDownload'])
20

  
21

  
22
    def backwards(self, orm):
23

  
24
        # Deleting model 'ClientDownload'
25
        db.delete_table('page_page_clientdownload')
26

  
27

  
28
    models = {
29
        'cloudcms.client': {
30
            'Meta': {'object_name': 'Client'},
31
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
32
            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
33
            'uid': ('django.db.models.fields.CharField', [], {'max_length': '255'})
34
        },
35
        'medialibrary.category': {
36
            'Meta': {'object_name': 'Category'},
37
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
38
            'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['medialibrary.Category']"}),
39
            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '150', 'db_index': 'True'}),
40
            'title': ('django.db.models.fields.CharField', [], {'max_length': '200'})
41
        },
42
        'medialibrary.mediafile': {
43
            'Meta': {'object_name': 'MediaFile'},
44
            'categories': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['medialibrary.Category']", 'null': 'True', 'blank': 'True'}),
45
            'copyright': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
46
            'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
47
            'file': ('django.db.models.fields.files.FileField', [], {'max_length': '255'}),
48
            'file_size': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
49
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
50
            'type': ('django.db.models.fields.CharField', [], {'max_length': '12'})
51
        },
52
        'page.aboutblock': {
53
            'Meta': {'object_name': 'AboutBlock', 'db_table': "'page_page_aboutblock'"},
54
            'color': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
55
            'content': ('django.db.models.fields.TextField', [], {}),
56
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
57
            'image': ('feincms.module.medialibrary.fields.MediaFileForeignKey', [], {'to': "orm['medialibrary.MediaFile']", 'null': 'True', 'blank': 'True'}),
58
            'image_position': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
59
            'offset_left': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
60
            'offset_top': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
61
            'ordering': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
62
            'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'aboutblock_set'", 'to': "orm['page.Page']"}),
63
            'region': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
64
            'title': ('django.db.models.fields.CharField', [], {'max_length': '200'})
65
        },
66
        'page.applicationcontent': {
67
            'Meta': {'object_name': 'ApplicationContent', 'db_table': "'page_page_applicationcontent'"},
68
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
69
            'ordering': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
70
            'parameters': ('feincms.contrib.fields.JSONField', [], {'null': 'True'}),
71
            'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'applicationcontent_set'", 'to': "orm['page.Page']"}),
72
            'region': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
73
            'urlconf_path': ('django.db.models.fields.CharField', [], {'max_length': '100'})
74
        },
75
        'page.clientdownload': {
76
            'Meta': {'object_name': 'ClientDownload', 'db_table': "'page_page_clientdownload'"},
77
            'client': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cloudcms.Client']"}),
78
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
79
            'ordering': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
80
            'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'clientdownload_set'", 'to': "orm['page.Page']"}),
81
            'region': ('django.db.models.fields.CharField', [], {'max_length': '255'})
82
        },
83
        'page.imagecontent': {
84
            'Meta': {'object_name': 'ImageContent', 'db_table': "'page_page_imagecontent'"},
85
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
86
            'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
87
            'ordering': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
88
            'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'imagecontent_set'", 'to': "orm['page.Page']"}),
89
            'position': ('django.db.models.fields.CharField', [], {'default': "'default'", 'max_length': '10'}),
90
            'region': ('django.db.models.fields.CharField', [], {'max_length': '255'})
91
        },
92
        'page.introbutton': {
93
            'Meta': {'object_name': 'IntroButton', 'db_table': "'page_page_introbutton'"},
94
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
95
            'image_1': ('feincms.module.medialibrary.fields.MediaFileForeignKey', [], {'blank': 'True', 'related_name': "'as_image1'", 'null': 'True', 'to': "orm['medialibrary.MediaFile']"}),
96
            'image_2': ('feincms.module.medialibrary.fields.MediaFileForeignKey', [], {'blank': 'True', 'related_name': "'as_image2'", 'null': 'True', 'to': "orm['medialibrary.MediaFile']"}),
97
            'image_3': ('feincms.module.medialibrary.fields.MediaFileForeignKey', [], {'blank': 'True', 'related_name': "'as_image3'", 'null': 'True', 'to': "orm['medialibrary.MediaFile']"}),
98
            'link': ('django.db.models.fields.CharField', [], {'default': "'/welcome'", 'max_length': '255'}),
99
            'link_title': ('django.db.models.fields.CharField', [], {'default': "'~okeanos'", 'max_length': '255'}),
100
            'ordering': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
101
            'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'introbutton_set'", 'to': "orm['page.Page']"}),
102
            'region': ('django.db.models.fields.CharField', [], {'max_length': '255'})
103
        },
104
        'page.latestentries': {
105
            'Meta': {'object_name': 'LatestEntries', 'db_table': "'page_page_latestentries'"},
106
            'display_text': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
107
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
108
            'limit': ('django.db.models.fields.PositiveIntegerField', [], {'default': '3'}),
109
            'ordering': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
110
            'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'latestentries_set'", 'to': "orm['page.Page']"}),
111
            'region': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
112
            'title': ('django.db.models.fields.CharField', [], {'max_length': '255'})
113
        },
114
        'page.loginform': {
115
            'Meta': {'object_name': 'LoginForm', 'db_table': "'page_page_loginform'"},
116
            'action_url': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
117
            'bottom_content': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
118
            'display_forgot_password': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
119
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
120
            'logged_in_content': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
121
            'next_url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
122
            'ordering': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
123
            'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'loginform_set'", 'to': "orm['page.Page']"}),
124
            'region': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
125
            'title': ('django.db.models.fields.CharField', [], {'max_length': '200'})
126
        },
127
        'page.mediafilecontent': {
128
            'Meta': {'object_name': 'MediaFileContent', 'db_table': "'page_page_mediafilecontent'"},
129
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
130
            'mediafile': ('feincms.module.medialibrary.fields.MediaFileForeignKey', [], {'related_name': "'+'", 'to': "orm['medialibrary.MediaFile']"}),
131
            'ordering': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
132
            'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'mediafilecontent_set'", 'to': "orm['page.Page']"}),
133
            'region': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
134
            'type': ('django.db.models.fields.CharField', [], {'default': "'lightbox'", 'max_length': '20'})
135
        },
136
        'page.page': {
137
            'Meta': {'object_name': 'Page'},
138
            '_cached_url': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'db_index': 'True', 'blank': 'True'}),
139
            '_content_title': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
140
            '_page_title': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
141
            'active': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
142
            'creation_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
143
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
144
            'in_navigation': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
145
            'language': ('django.db.models.fields.CharField', [], {'default': "'en'", 'max_length': '10'}),
146
            'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
147
            'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
148
            'meta_description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
149
            'meta_keywords': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
150
            'modification_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
151
            'navigation_extension': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
152
            'override_url': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
153
            'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['page.Page']"}),
154
            'publication_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 5, 4, 11, 30)'}),
155
            'publication_end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
156
            'redirect_to': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
157
            'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
158
            'site': ('django.db.models.fields.related.ForeignKey', [], {'default': '1', 'to': "orm['sites.Site']"}),
159
            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '150', 'db_index': 'True'}),
160
            'symlinked_page': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'page_page_symlinks'", 'null': 'True', 'to': "orm['page.Page']"}),
161
            'template_key': ('django.db.models.fields.CharField', [], {'default': "'basic'", 'max_length': '255'}),
162
            'title': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
163
            'translation_of': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'translations'", 'null': 'True', 'to': "orm['page.Page']"}),
164
            'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'})
165
        },
166
        'page.rawcontent': {
167
            'Meta': {'object_name': 'RawContent', 'db_table': "'page_page_rawcontent'"},
168
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
169
            'ordering': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
170
            'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rawcontent_set'", 'to': "orm['page.Page']"}),
171
            'region': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
172
            'text': ('django.db.models.fields.TextField', [], {'blank': 'True'})
173
        },
174
        'page.resourceslist': {
175
            'Meta': {'object_name': 'ResourcesList', 'db_table': "'page_page_resourceslist'"},
176
            'filter_title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
177
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
178
            'ordering': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
179
            'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'resourceslist_set'", 'to': "orm['page.Page']"}),
180
            'region': ('django.db.models.fields.CharField', [], {'max_length': '255'})
181
        },
182
        'page.richtextcontent': {
183
            'Meta': {'object_name': 'RichTextContent', 'db_table': "'page_page_richtextcontent'"},
184
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
185
            'ordering': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
186
            'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'richtextcontent_set'", 'to': "orm['page.Page']"}),
187
            'region': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
188
            'text': ('django.db.models.fields.TextField', [], {'blank': 'True'})
189
        },
190
        'page.sectioncontent': {
191
            'Meta': {'object_name': 'SectionContent', 'db_table': "'page_page_sectioncontent'"},
192
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
193
            'mediafile': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'page_sectioncontent_set'", 'null': 'True', 'to': "orm['medialibrary.MediaFile']"}),
194
            'ordering': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
195
            'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'sectioncontent_set'", 'to': "orm['page.Page']"}),
196
            'region': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
197
            'richtext': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
198
            'title': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
199
            'type': ('django.db.models.fields.CharField', [], {'default': "'block'", 'max_length': '10'})
200
        },
201
        'page.templatecontent': {
202
            'Meta': {'object_name': 'TemplateContent', 'db_table': "'page_page_templatecontent'"},
203
            'filename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
204
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
205
            'ordering': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
206
            'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'templatecontent_set'", 'to': "orm['page.Page']"}),
207
            'region': ('django.db.models.fields.CharField', [], {'max_length': '255'})
208
        },
209
        'page.twitterfeed': {
210
            'Meta': {'object_name': 'TwitterFeed', 'db_table': "'page_page_twitterfeed'"},
211
            'account': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
212
            'avatar': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
213
            'extra_params': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
214
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
215
            'limit': ('django.db.models.fields.PositiveIntegerField', [], {'default': '10'}),
216
            'nots': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
217
            'ordering': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
218
            'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'twitterfeed_set'", 'to': "orm['page.Page']"}),
219
            'query': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
220
            'region': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
221
            'replies': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
222
            'retweets': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
223
            'tag': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
224
            'title': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'})
225
        },
226
        'page.videocontent': {
227
            'Meta': {'object_name': 'VideoContent', 'db_table': "'page_page_videocontent'"},
228
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
229
            'ordering': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
230
            'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'videocontent_set'", 'to': "orm['page.Page']"}),
231
            'region': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
232
            'video': ('django.db.models.fields.URLField', [], {'max_length': '200'})
233
        },
234
        'page.videosection': {
235
            'Meta': {'object_name': 'VideoSection', 'db_table': "'page_page_videosection'"},
236
            'alt_text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
237
            'extra_url_params': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
238
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
239
            'image': ('feincms.module.medialibrary.fields.MediaFileForeignKey', [], {'blank': 'True', 'related_name': "'as_image_for_video_section'", 'null': 'True', 'to': "orm['medialibrary.MediaFile']"}),
240
            'image_hover': ('feincms.module.medialibrary.fields.MediaFileForeignKey', [], {'blank': 'True', 'related_name': "'as_hover_for_video_section'", 'null': 'True', 'to': "orm['medialibrary.MediaFile']"}),
241
            'ordering': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
242
            'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'videosection_set'", 'to': "orm['page.Page']"}),
243
            'region': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
244
            'section_title': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
245
            'video_height': ('django.db.models.fields.PositiveIntegerField', [], {'default': '550'}),
246
            'video_link': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
247
            'video_title': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
248
            'video_width': ('django.db.models.fields.PositiveIntegerField', [], {'default': '700'})
249
        },
250
        'sites.site': {
251
            'Meta': {'object_name': 'Site', 'db_table': "'django_site'"},
252
            'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
253
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
254
            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
255
        }
256
    }
257

  
258
    complete_apps = ['page']
b/cloudcms/migrations/0006_auto__add_clientversionsource__add_client.py
1
# encoding: utf-8
2
import datetime
3
from south.db import db
4
from south.v2 import SchemaMigration
5
from django.db import models
6

  
7
class Migration(SchemaMigration):
8
    
9
    def forwards(self, orm):
10
        
11
        # Adding model 'ClientVersionSource'
12
        db.create_table('cloudcms_clientversionsource', (
13
            ('source_type', self.gf('django.db.models.fields.CharField')(max_length=60)),
14
            ('link', self.gf('django.db.models.fields.CharField')(max_length=255)),
15
            ('architecture', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True)),
16
            ('logo', self.gf('feincms.module.medialibrary.fields.MediaFileForeignKey')(to=orm['medialibrary.MediaFile'], null=True, blank=True)),
17
            ('os', self.gf('django.db.models.fields.CharField')(max_length=255)),
18
            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
19
        ))
20
        db.send_create_signal('cloudcms', ['ClientVersionSource'])
21

  
22
        # Adding model 'Client'
23
        db.create_table('cloudcms_client', (
24
            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
25
            ('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
26
            ('uid', self.gf('django.db.models.fields.CharField')(max_length=255)),
27
        ))
28
        db.send_create_signal('cloudcms', ['Client'])
29

  
30
        # Adding M2M table for field sources on 'Client'
31
        db.create_table('cloudcms_client_sources', (
32
            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
33
            ('client', models.ForeignKey(orm['cloudcms.client'], null=False)),
34
            ('clientversionsource', models.ForeignKey(orm['cloudcms.clientversionsource'], null=False))
35
        ))
36
        db.create_unique('cloudcms_client_sources', ['client_id', 'clientversionsource_id'])
37
    
38
    
39
    def backwards(self, orm):
40
        
41
        # Deleting model 'ClientVersionSource'
42
        db.delete_table('cloudcms_clientversionsource')
43

  
44
        # Deleting model 'Client'
45
        db.delete_table('cloudcms_client')
46

  
47
        # Removing M2M table for field sources on 'Client'
48
        db.delete_table('cloudcms_client_sources')
49
    
50
    
51
    models = {
52
        'cloudcms.application': {
53
            'Meta': {'object_name': 'Application'},
54
            'app_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
55
            'code': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
56
            'extra_styles': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
57
            'facebook_username': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
58
            'favicon': ('feincms.module.medialibrary.fields.MediaFileForeignKey', [], {'blank': 'True', 'related_name': "'as_favicon'", 'null': 'True', 'to': "orm['medialibrary.MediaFile']"}),
59
            'footer_bottom': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
60
            'footer_top': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
61
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
62
            'index_url': ('django.db.models.fields.CharField', [], {'default': "'/'", 'max_length': '255'}),
63
            'linked_in_username': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
64
            'logo': ('feincms.module.medialibrary.fields.MediaFileForeignKey', [], {'to': "orm['medialibrary.MediaFile']", 'null': 'True', 'blank': 'True'}),
65
            'show_twitter_feed_on_top': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
66
            'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}),
67
            'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
68
            'twitter_username': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'})
69
        },
70
        'cloudcms.client': {
71
            'Meta': {'object_name': 'Client'},
72
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
73
            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
74
            'sources': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['cloudcms.ClientVersionSource']", 'symmetrical': 'False'}),
75
            'uid': ('django.db.models.fields.CharField', [], {'max_length': '255'})
76
        },
77
        'cloudcms.clientversionsource': {
78
            'Meta': {'object_name': 'ClientVersionSource'},
79
            'architecture': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
80
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
81
            'link': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
82
            'logo': ('feincms.module.medialibrary.fields.MediaFileForeignKey', [], {'to': "orm['medialibrary.MediaFile']", 'null': 'True', 'blank': 'True'}),
83
            'os': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
84
            'source_type': ('django.db.models.fields.CharField', [], {'max_length': '60'})
85
        },
86
        'medialibrary.category': {
87
            'Meta': {'object_name': 'Category'},
88
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
89
            'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['medialibrary.Category']"}),
90
            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '150', 'db_index': 'True'}),
91
            'title': ('django.db.models.fields.CharField', [], {'max_length': '200'})
92
        },
93
        'medialibrary.mediafile': {
94
            'Meta': {'object_name': 'MediaFile'},
95
            'categories': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['medialibrary.Category']", 'null': 'True', 'blank': 'True'}),
96
            'copyright': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
97
            'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
98
            'file': ('django.db.models.fields.files.FileField', [], {'max_length': '255'}),
99
            'file_size': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
100
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
101
            'type': ('django.db.models.fields.CharField', [], {'max_length': '12'})
102
        },
103
        'sites.site': {
104
            'Meta': {'object_name': 'Site', 'db_table': "'django_site'"},
105
            'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
106
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
107
            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
108
        }
109
    }
110
    
111
    complete_apps = ['cloudcms']
b/cloudcms/migrations/0007_auto__add_field_clientversionsource_client.py
1
# encoding: utf-8
2
import datetime
3
from south.db import db
4
from south.v2 import SchemaMigration
5
from django.db import models
6

  
7
class Migration(SchemaMigration):
8
    
9
    def forwards(self, orm):
10
        
11
        # Adding field 'ClientVersionSource.client'
12
        db.add_column('cloudcms_clientversionsource', 'client', self.gf('django.db.models.fields.related.ForeignKey')(default=1, to=orm['cloudcms.Client']), keep_default=False)
13

  
14
        # Removing M2M table for field sources on 'Client'
15
        db.delete_table('cloudcms_client_sources')
16
    
17
    
18
    def backwards(self, orm):
19
        
20
        # Deleting field 'ClientVersionSource.client'
21
        db.delete_column('cloudcms_clientversionsource', 'client_id')
22

  
23
        # Adding M2M table for field sources on 'Client'
24
        db.create_table('cloudcms_client_sources', (
25
            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
26
            ('client', models.ForeignKey(orm['cloudcms.client'], null=False)),
27
            ('clientversionsource', models.ForeignKey(orm['cloudcms.clientversionsource'], null=False))
28
        ))
29
        db.create_unique('cloudcms_client_sources', ['client_id', 'clientversionsource_id'])
30
    
31
    
32
    models = {
33
        'cloudcms.application': {
34
            'Meta': {'object_name': 'Application'},
35
            'app_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
36
            'code': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
37
            'extra_styles': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
38
            'facebook_username': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
39
            'favicon': ('feincms.module.medialibrary.fields.MediaFileForeignKey', [], {'blank': 'True', 'related_name': "'as_favicon'", 'null': 'True', 'to': "orm['medialibrary.MediaFile']"}),
40
            'footer_bottom': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
41
            'footer_top': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
42
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
43
            'index_url': ('django.db.models.fields.CharField', [], {'default': "'/'", 'max_length': '255'}),
44
            'linked_in_username': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
45
            'logo': ('feincms.module.medialibrary.fields.MediaFileForeignKey', [], {'to': "orm['medialibrary.MediaFile']", 'null': 'True', 'blank': 'True'}),
46
            'show_twitter_feed_on_top': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
47
            'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}),
48
            'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
49
            'twitter_username': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'})
50
        },
51
        'cloudcms.client': {
52
            'Meta': {'object_name': 'Client'},
53
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
54
            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
55
            'uid': ('django.db.models.fields.CharField', [], {'max_length': '255'})
56
        },
57
        'cloudcms.clientversionsource': {
58
            'Meta': {'object_name': 'ClientVersionSource'},
59
            'architecture': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
60
            'client': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cloudcms.Client']"}),
61
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
62
            'link': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
63
            'logo': ('feincms.module.medialibrary.fields.MediaFileForeignKey', [], {'to': "orm['medialibrary.MediaFile']", 'null': 'True', 'blank': 'True'}),
64
            'os': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
65
            'source_type': ('django.db.models.fields.CharField', [], {'max_length': '60'})
66
        },
67
        'medialibrary.category': {
68
            'Meta': {'object_name': 'Category'},
69
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
70
            'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['medialibrary.Category']"}),
71
            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '150', 'db_index': 'True'}),
72
            'title': ('django.db.models.fields.CharField', [], {'max_length': '200'})
73
        },
74
        'medialibrary.mediafile': {
75
            'Meta': {'object_name': 'MediaFile'},
76
            'categories': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['medialibrary.Category']", 'null': 'True', 'blank': 'True'}),
77
            'copyright': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
78
            'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
79
            'file': ('django.db.models.fields.files.FileField', [], {'max_length': '255'}),
80
            'file_size': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
81
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
82
            'type': ('django.db.models.fields.CharField', [], {'max_length': '12'})
83
        },
84
        'sites.site': {
85
            'Meta': {'object_name': 'Site', 'db_table': "'django_site'"},
86
            'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
87
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
88
            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
89
        }
90
    }
91
    
92
    complete_apps = ['cloudcms']
b/cloudcms/migrations/0008_auto__add_field_clientversionsource_file_regex__add_field_clientversio.py
1
# encoding: utf-8
2
import datetime
3
from south.db import db
4
from south.v2 import SchemaMigration
5
from django.db import models
6

  
7
class Migration(SchemaMigration):
8
    
9
    def forwards(self, orm):
10
        
11
        # Adding field 'ClientVersionSource.file_regex'
12
        db.add_column('cloudcms_clientversionsource', 'file_regex', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True), keep_default=False)
13

  
14
        # Adding field 'ClientVersionSource.version_regex'
15
        db.add_column('cloudcms_clientversionsource', 'version_regex', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True), keep_default=False)
16
    
17
    
18
    def backwards(self, orm):
19
        
20
        # Deleting field 'ClientVersionSource.file_regex'
21
        db.delete_column('cloudcms_clientversionsource', 'file_regex')
22

  
23
        # Deleting field 'ClientVersionSource.version_regex'
24
        db.delete_column('cloudcms_clientversionsource', 'version_regex')
25
    
26
    
27
    models = {
28
        'cloudcms.application': {
29
            'Meta': {'object_name': 'Application'},
30
            'app_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
31
            'code': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
32
            'extra_styles': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
33
            'facebook_username': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
34
            'favicon': ('feincms.module.medialibrary.fields.MediaFileForeignKey', [], {'blank': 'True', 'related_name': "'as_favicon'", 'null': 'True', 'to': "orm['medialibrary.MediaFile']"}),
35
            'footer_bottom': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
36
            'footer_top': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
37
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
38
            'index_url': ('django.db.models.fields.CharField', [], {'default': "'/'", 'max_length': '255'}),
39
            'linked_in_username': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
40
            'logo': ('feincms.module.medialibrary.fields.MediaFileForeignKey', [], {'to': "orm['medialibrary.MediaFile']", 'null': 'True', 'blank': 'True'}),
41
            'show_twitter_feed_on_top': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
42
            'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}),
43
            'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
44
            'twitter_username': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'})
45
        },
46
        'cloudcms.client': {
47
            'Meta': {'object_name': 'Client'},
48
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
49
            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
50
            'uid': ('django.db.models.fields.CharField', [], {'max_length': '255'})
51
        },
52
        'cloudcms.clientversionsource': {
53
            'Meta': {'object_name': 'ClientVersionSource'},
54
            'architecture': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
55
            'client': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cloudcms.Client']"}),
56
            'file_regex': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
57
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
58
            'link': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
59
            'logo': ('feincms.module.medialibrary.fields.MediaFileForeignKey', [], {'to': "orm['medialibrary.MediaFile']", 'null': 'True', 'blank': 'True'}),
60
            'os': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
61
            'source_type': ('django.db.models.fields.CharField', [], {'max_length': '60'}),
62
            'version_regex': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'})
63
        },
64
        'medialibrary.category': {
65
            'Meta': {'object_name': 'Category'},
66
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
67
            'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['medialibrary.Category']"}),
68
            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '150', 'db_index': 'True'}),
69
            'title': ('django.db.models.fields.CharField', [], {'max_length': '200'})
70
        },
71
        'medialibrary.mediafile': {
72
            'Meta': {'object_name': 'MediaFile'},
73
            'categories': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['medialibrary.Category']", 'null': 'True', 'blank': 'True'}),
74
            'copyright': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
75
            'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
76
            'file': ('django.db.models.fields.files.FileField', [], {'max_length': '255'}),
77
            'file_size': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
78
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
79
            'type': ('django.db.models.fields.CharField', [], {'max_length': '12'})
80
        },
81
        'sites.site': {
82
            'Meta': {'object_name': 'Site', 'db_table': "'django_site'"},
83
            'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
84
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
85
            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
86
        }
87
    }
88
    
89
    complete_apps = ['cloudcms']
b/cloudcms/models.py
31 31
# interpreted as representing official policies, either expressed
32 32
# or implied, of GRNET S.A.
33 33

  
34
import datetime
34 35

  
35 36
from django.db import models
36 37
from django.conf import settings
37 38
from django.contrib.sites import models as sites_models
39
from django.core.cache import cache
40
from django.utils import simplejson
38 41

  
39 42
from feincms.module.medialibrary.fields import MediaFileForeignKey
40 43
from feincms.module.medialibrary.models import MediaFile
41 44

  
42 45

  
43 46
class Application(models.Model):
47
    """
48
    Application object refers to the application each cms is deployed for.
49

  
50
    Each cms deployment should contain at least one application object linked
51
    to the site object the cms is deployed for.
52

  
53
    Enabling cloudcms.context_processors.application in CONTEXT_PROCESSROS setting
54
    let you can access the application object throughout the html templates.
55
    """
44 56
    code = models.CharField('Identifier', max_length=100, null=False, blank=False,
45 57
            help_text="Just a codename of the application, to be used in "\
46 58
                    "several places where no free text is allowed"\
......
74 86
        return self.title
75 87

  
76 88

  
89
# http://stackoverflow.com/a/2680060/114435
90
dthandler = lambda obj: obj.isoformat() if isinstance(obj, datetime.datetime) else None
91

  
92
class Client(models.Model):
93
    """
94
    Model which refers to a service/application client. Client model contains
95
    multiple ClientVersionSource to identify it's version downloads.
96
    """
97
    uid = models.CharField(max_length=255)
98
    name = models.CharField(max_length=255)
99

  
100
    def get_sources(self):
101
        sources = {}
102
        from cloudcms.clients import ClientVersions
103
        for s in self.clientversionsource_set.all():
104
            sources[s.os] = {'type': s.source_type,
105
                             'args': [s.link]}
106

  
107
        return ClientVersions(sources, cache_backend=cache)
108

  
109
    def to_json(self):
110
        return simplejson.dumps(list(self.get_sources().get_latest_versions()),
111
                default=dthandler)
112

  
113
    def __unicode__(self):
114
        return self.name
115

  
116

  
117
class ClientVersionSource(models.Model):
118
    """
119
    Client version source. source_type choices should map to
120
    cloudcms.clients.SOURCE_TYPES.
121
    """
122
    source_type = models.CharField(max_length=60,
123
            choices=(('link','Link'),
124
                     ('direct','Direct'),
125
                     ('redmine_files','Redmine files')))
126
    os = models.CharField(max_length=255)
127
    link = models.CharField(max_length=255)
128
    logo = MediaFileForeignKey(MediaFile, blank=True, null=True)
129
    architecture = models.CharField(max_length=255, null=True, blank=True,
130
            help_text="""Depending the source type this can be left empty and
131
            let source type identify the architecture""")
132
    client = models.ForeignKey(Client)
133
    version_regex = models.CharField(max_length=255, help_text="""Regular expression to
134
            match the version of the file based on retrieved source filenames
135
            (used in redmine source types)""", null=True, blank=True)
136
    file_regex = models.CharField(max_length=255, help_text="""Return only files that
137
            match this expression""", null=True, blank=True)
138

  
139
    def __unicode__(self):
140
        return "[%s] %s" % (self.get_source_type_display(), self.os)
141

  
142

  
77 143
# hook for feincms configuration, is this appropriate place ??? who knows
78 144
from cloudcms.cms import *
79 145

  
b/cloudcms/static/cloudcms/js/client-downloads.js
1
var ClientDownloads = function(wrapper, clients) {
2
    this.el = $(wrapper);
3
    this.clients = clients;
4
}
5

  
6
ClientDownloads.prototype.update = function() {
7
    console.log("updating clients");
8
}
9

  
b/cloudcms/templates/content/client_downloads.html
1
<div class="clients-wrapper">
2
    <ul>
3
    </ul>
4
</div>
5

  
6
<script>
7
    $(document).ready(function(){
8
        if (window.ClientDownloads) {
9
            var clients_data = {{ content.client.to_json|safe }};
10
            var clients = new ClientDownloads(".clients-wrapper", clients_data);
11
            clients.update();
12
        }
13
    })
14
</script>

Also available in: Unified diff