]> git.openstreetmap.org Git - osqa.git/blob - forum_modules/updates/base.py
Fix OSQA-819: Link to profile in message is wrong if OSQA is installed in a subfolder
[osqa.git] / forum_modules / updates / base.py
1 # -*- coding: utf-8 -*-
2
3 import os
4 import sys
5 import platform
6 import bz2
7 import urllib2, urllib
8 import binascii
9 import string
10 import random
11 import re
12 import urllib2
13 import settings
14 import datetime
15 import logging
16
17
18 from xml.dom.minidom import parse, parseString
19 from forum.base import get_database_engine
20 from forum.models import Question, Answer, Comment, User
21 from forum.settings import APP_URL, VCS_REVISION, APP_TITLE, APP_DESCRIPTION
22 from django import VERSION as DJANGO_VERSION
23 from django.utils.html import escape
24 from django.utils.encoding import smart_unicode
25 from django.conf import settings as django_settings
26 from django.utils.translation import ugettext as _
27
28
29 def generate_installation_key():
30     gen = lambda length: "".join( [random.choice(string.digits+string.letters) for i in xrange(length)])
31     return '%s-%s-%s-%s' % (gen(4), gen(4), gen(4), gen(4))
32
33 # To get the site views count we get the SUM of all questions views.
34 def get_site_views():
35     views = 0
36
37     # Go through all questions and increase the views count
38     for question in Question.objects.all():
39         views += question.view_count
40
41     return views
42
43 # Gets the active users count since the last visit
44 def get_active_users():
45     users_count = 0
46
47     try:
48         if settings.LATEST_UPDATE_DATETIME:
49             users_count = User.objects.filter(last_login__gt=settings.LATEST_UPDATE_DATETIME).count()
50     except:
51         pass
52
53     return users_count
54
55 def get_server_name():
56     url = '%s/' % APP_URL
57
58     try:
59         # Make the request
60         request = urllib2.Request(url)
61         response = urllib2.urlopen(request)
62
63         # Get the response information
64         response_info = response.info()
65
66         server_name = re.findall("Server: (?P<server_name>.*)$", str(response_info))[0]
67         server_name = ''.join(server_name.splitlines())
68
69         return server_name
70     except:
71         return 'Unknown'
72
73 def get_admin_emails():
74     emails = []
75
76     for user in User.objects.filter(is_superuser=True):
77         emails.append(user.email)
78
79     return emails
80
81 def check_for_updates():
82     # Get the SVN Revision
83     try:
84         svn_revision = int(VCS_REVISION.replace('SVN-', ''))
85     except ValueError:
86         # Here we'll have to find another way of getting the SVN revision
87         svn_revision = 0
88
89     admin_emails_xml = '<emails>'
90     for email in get_admin_emails():
91         admin_emails_xml += '<email value="%s" />' % email
92     admin_emails_xml += '</emails>'
93
94     database_type = get_database_engine()
95
96     statistics = u"""<check>
97     <key value="%(site_key)s" />
98     <app_url value="%(app_url)s" />
99     <app_title value="%(app_title)s" />
100     <app_description value="%(app_description)s" />
101     <svn_revision value="%(svn_revision)d" />
102     <views value="%(site_views)d" />
103     <questions_count value="%(questions_count)d" />
104     <answers_count value="%(answers_count)d" />
105     <comments_count value="%(comments_count)d" />
106     <active_users value="%(active_users)d" />
107     <server value="%(server_name)s" />
108     <python_version value="%(python_version)s" />
109     <django_version value="%(django_version)s" />
110     <database value="%(database)s" />
111     <os value="%(os)s" />
112     %(emails)s
113 </check> """ % {
114         'site_key' : settings.SITE_KEY,
115         'app_url' : APP_URL,
116         'app_title' : escape(APP_TITLE.value),
117         'app_description' : escape(APP_DESCRIPTION.value),
118         'svn_revision' : svn_revision,
119         'site_views' : get_site_views(),
120         'server_name' : get_server_name(),
121         'questions_count' : Question.objects.filter_state(deleted=False).count(),
122         'answers_count' : Answer.objects.filter_state(deleted=False).count(),
123         'comments_count' : Comment.objects.filter_state(deleted=False).count(),
124         'active_users' : get_active_users(),
125         'python_version' : ''.join(sys.version.splitlines()),
126         'django_version' : str(DJANGO_VERSION),
127         'database' : database_type,
128         'os' : str(platform.uname()),
129         'emails' : admin_emails_xml,
130     }
131
132     # Compress the statistics XML dump
133     statistics = statistics.encode('ascii', 'xmlcharrefreplace')
134     statistics_compressed = bz2.compress(statistics)
135
136     # Pass the compressed statistics to the update server
137     post_data = {
138         'statistics' : binascii.b2a_base64(statistics_compressed),
139     }
140     data = urllib.urlencode(post_data)
141
142     # We simulate some browser, otherwise the server can return 403 response
143     user_agent = 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-us) AppleWebKit/531.21.8 (KHTML, like Gecko) Version/4.0.4 Safari/5'
144     headers={ 'User-Agent' : user_agent,}
145
146     try:
147         check_request = urllib2.Request('%s%s' % (settings.UPDATE_SERVER_URL, '/site_check/'), data, headers=headers)
148         check_response = urllib2.urlopen(check_request)
149         content = check_response.read()
150     except urllib2.HTTPError, error:
151         content = error.read()
152     except:
153         return _("Wasn't able to check to the update server.")
154
155     # Read the messages from the Update Server
156     try:
157         messages_xml_url = '%s%s' % (settings.UPDATE_SERVER_URL, '/messages/xml/')
158         messages_request = urllib2.Request(messages_xml_url, headers=headers)
159         messages_response = urllib2.urlopen(messages_request)
160         messages_xml = messages_response.read()
161     except:
162         return _("Wasn't able to retreive the update messages.")
163
164     # Store the messages XML in a Setting object
165     settings.UPDATE_MESSAGES_XML.set_value(messages_xml)
166
167     messages_dom = parseString(messages_xml)
168     messages_count = len(messages_dom.getElementsByTagName('message'))
169
170     # Set the latest update datetime to now.
171     now = datetime.datetime.now()
172     settings.LATEST_UPDATE_DATETIME.set_value(now)
173
174     return _('%d update messages have been downloaded.') % messages_count
175
176 def update_trigger():
177     # Trigger the update process
178     now = datetime.datetime.now()
179     if (now - settings.LATEST_UPDATE_DATETIME) > datetime.timedelta(days=1):
180         try:
181             update_status = check_for_updates()
182             logging.log(logging.INFO, smart_unicode("Update process has been triggered: %s" % update_status))
183         except Exception, e:
184             logging.errror(smart_unicode(e))
185         finally:
186             settings.LATEST_UPDATE_DATETIME.set_value(now)