Merge lp:~the-dod/sahana-eden/twitter-oauth into lp:sahana-eden

Proposed by The Dod
Status: Superseded
Proposed branch: lp:~the-dod/sahana-eden/twitter-oauth
Merge into: lp:sahana-eden
Diff against target: 329 lines (+153/-29)
7 files modified
controllers/msg.py (+78/-16)
cron/crontab (+2/-2)
models/000_config.py (+17/-9)
models/00_utils.py (+1/-1)
models/01_menu.py (+1/-0)
models/msg.py (+47/-1)
modules/s3cfg.py (+7/-0)
To merge this branch: bzr merge lp:~the-dod/sahana-eden/twitter-oauth
Reviewer Review Type Date Requested Status
Fran Boon Pending
Review via email: mp+38120@code.launchpad.net

This proposal supersedes a proposal from 2010-10-11.

This proposal has been superseded by a proposal from 2010-10-11.

Description of the change

Twitter-OAuth integration, phase 1.
See comment on the commit.
Hope I'm doing everything right being new to s3 and all :)

To post a comment you must log in.
1348. By Fran Boon

Merge thedod: Twitter OAuth support using tweepy. Also did general cleanup of Messaging

1349. By The Dod <nonboong@nobita>

Merge with Fran et al

1350. By The Dod <nonboong@nobita>

Proposal to separate deployment-specific files from version-control

In order to prevent leaks of deployment-specific information into the
repoository, I propose to track *templates* of these files instead.
After installation, admin should run ./run_me_once.sh
to create *untracked* versions of these files where passwords etc.
can be safely entered.

1351. By The Dod <nonboong@nobita>

Merge with trunk

1352. By The Dod <nonboong@nobita>

revert to before skeletons proposal

1353. By The Dod <nonboong@nobita>

Wrote the whole twitter sending bit

Sadly - however - it doesn't work.
Got text waiting to be tweeted in the outbox, and the cron doesn't seem
to pick it up. Committing this so that I can bitch about it in irc :)

Unmerged revisions

1353. By The Dod <nonboong@nobita>

Wrote the whole twitter sending bit

Sadly - however - it doesn't work.
Got text waiting to be tweeted in the outbox, and the cron doesn't seem
to pick it up. Committing this so that I can bitch about it in irc :)

1352. By The Dod <nonboong@nobita>

revert to before skeletons proposal

1351. By The Dod <nonboong@nobita>

Merge with trunk

1350. By The Dod <nonboong@nobita>

Proposal to separate deployment-specific files from version-control

In order to prevent leaks of deployment-specific information into the
repoository, I propose to track *templates* of these files instead.
After installation, admin should run ./run_me_once.sh
to create *untracked* versions of these files where passwords etc.
can be safely entered.

1349. By The Dod <nonboong@nobita>

Merge with Fran et al

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'controllers/msg.py'
2--- controllers/msg.py 2010-10-10 05:06:31 +0000
3+++ controllers/msg.py 2010-10-11 14:11:40 +0000
4@@ -12,13 +12,13 @@
5
6 # Options Menu (available in all Functions' Views)
7 response.menu_options = [
8- [T("Compose"), False, URL(r=request, c="msg", f="compose")],
9- [T("Distribution groups"), False, URL(r=request, f="group"), [
10- [T("List/Add"), False, URL(r=request, f="group")],
11- [T("Group Memberships"), False, URL(r=request, f="group_membership")],
12- ]],
13- [T("Log"), False, URL(r=request, f="log")],
14- [T("Outbox"), False, URL(r=request, f="outbox")],
15+ [T("Compose"), False, URL(r=request, c="msg", f="compose")],
16+ [T("Distribution groups"), False, URL(r=request, f="group"), [
17+ [T("List/Add"), False, URL(r=request, f="group")],
18+ [T("Group Memberships"), False, URL(r=request, f="group_membership")],
19+ ]],
20+ [T("Log"), False, URL(r=request, f="log")],
21+ [T("Outbox"), False, URL(r=request, f="outbox")],
22 #["CAP", False, URL(r=request, f="tbc")]
23 ]
24
25@@ -228,8 +228,8 @@
26 _title=T("Delete") + "|" + T("If this is set to True then mails will be deleted from the server after downloading.")))
27
28 if not auth.has_membership(auth.id_group("Administrator")):
29- session.error = UNAUTHORISED
30- redirect(URL(r=request, f="index"))
31+ session.error = UNAUTHORISED
32+ redirect(URL(r=request, f="index"))
33 # CRUD Strings
34 ADD_SETTING = T("Add Setting")
35 VIEW_SETTINGS = T("View Settings")
36@@ -251,6 +251,69 @@
37 response.menu_options = admin_menu_options
38 return shn_rest_controller(module, "email_settings", listadd=False, deletable=False)
39
40+@auth.shn_requires_membership(1)
41+def twitter_settings():
42+ """ RESTful CRUD controller for twitter settings - appears in the administration menu """
43+
44+ # CRUD Strings
45+ ADD_SETTING = T("Add Setting")
46+ VIEW_SETTINGS = T("View Settings")
47+ s3.crud_strings[tablename] = Storage(
48+ title_create = ADD_SETTING,
49+ title_display = T("Setting Details"),
50+ title_list = VIEW_SETTINGS,
51+ title_update = T("Authenticate system's Twitter account"),
52+ title_search = T("Search Settings"),
53+ subtitle_list = T("Settings"),
54+ label_list_button = VIEW_SETTINGS,
55+ label_create_button = ADD_SETTING,
56+ msg_record_created = T("Setting added"),
57+ msg_record_modified = T("System's Twitter account updated"),
58+ msg_record_deleted = T("Setting deleted"),
59+ msg_list_empty = T("No Settings currently defined")
60+ )
61+
62+ def prep(jr):
63+ if not (deployment_settings.oauth.consumer_key and deployment_settings.oauth.consumer_secret):
64+ session.error=T("You should edit oauth_settings at models/000_config.py")
65+ return True
66+ try:
67+ import tweepy
68+ except:
69+ session.error=T("Couldn't import tweepy library")
70+ return True
71+ oauth = tweepy.OAuthHandler(deployment_settings.oauth.consumer_key,
72+ deployment_settings.oauth.consumer_secret)
73+
74+ resource = request.function
75+ tablename = module + "_" + resource
76+ table = db[tablename]
77+
78+ if jr.http == "GET":
79+ try:
80+ session.s3.twitter_oauth_url = oauth.get_authorization_url()
81+ session.s3.twitter_request_key = oauth.request_token.key
82+ session.s3.twitter_request_secret = oauth.request_token.secret
83+ except tweepy.TweepError:
84+ session.error=T("problem connecting to twitter.com")
85+ return True
86+ table.pin.label = SPAN(T("PIN number "),
87+ A(T("from Twitter"), _href=T(session.s3.twitter_oauth_url), _target="_blank"),
88+ T(" (leave empty to detach account)"))
89+ table.pin.value = ""
90+ table.twitter_account.label = T("Current twitter account")
91+ else: # POST
92+ table.pin.label = T("PIN")
93+ table.pin.value = ""
94+ table.oauth_key.label = T("OAuth key")
95+ table.oauth_secret.label = T("OAuth secret")
96+ return True
97+ response.s3.prep = prep
98+
99+ response.menu_options = admin_menu_options
100+ return shn_rest_controller(module, "twitter_settings", listadd=False, deletable=False)
101+
102+
103 #--------------------------------------------------------------------------------------------------
104
105 # The following 2 functions hook into the pr functions
106@@ -395,16 +458,16 @@
107 return item
108
109 def process_sms_via_api():
110- "Controller for SMS api processing - to be called via cron"
111+ "Controller for SMS api processing - to be called via cron"
112
113- msg.process_outbox(contact_method = 2)
114- return
115+ msg.process_outbox(contact_method = 2)
116+ return
117
118 def process_email_via_api():
119- "Controller for Email api processing - to be called via cron"
120+ "Controller for Email api processing - to be called via cron"
121
122- msg.process_outbox(contact_method = 1)
123- return
124+ msg.process_outbox(contact_method = 1)
125+ return
126
127 def process_sms_via_tropo():
128 "Controller for SMS tropo processing - to be called via cron"
129@@ -632,4 +695,3 @@
130 response.s3.pagination = True
131
132 return shn_rest_controller(module, resource, listadd=False)
133-
134
135=== modified file 'cron/crontab'
136--- cron/crontab 2010-10-10 20:04:29 +0000
137+++ cron/crontab 2010-10-11 14:11:40 +0000
138@@ -5,9 +5,9 @@
139 #@reboot root *applications/eden/cron/sms_handler_modem.py
140 # Synchronisation
141 #@reboot root *sync/schedule_cron
142-0 * * * * root *sync/sync_cron
143+0 * * * * web2py *sync/sync_cron
144 # Send outgoing emails every 5 minutes
145-#*/5 * * * * root *msg/process_email_via_api
146+*/5 * * * * web2py *msg/process_email_via_api
147 # Send outgoing SMS every 5 minutes
148 #*/5 * * * * root *msg/process_sms_via_api
149 # Send outgoing Tropo SMS every 5 minutes
150
151=== modified file 'models/000_config.py'
152--- models/000_config.py 2010-10-10 10:16:05 +0000
153+++ models/000_config.py 2010-10-11 14:11:40 +0000
154@@ -27,6 +27,14 @@
155 deployment_settings.auth.registration_requires_approval = False
156 deployment_settings.auth.openid = False
157
158+# Twitter OAuth settings:
159+# Register an app at http://twitter.com/apps
160+# (select Aplication Type: Client)
161+# You'll get your consumer_key and consumer_secret from twitter
162+# Keep these empty if you don't need twitter integration
163+deployment_settings.oauth.consumer_key=""
164+deployment_settings.oauth.consumer_secret=""
165+
166 # Base settings
167 # Set this to the Public URL of the instance
168 deployment_settings.base.public_url = "http://127.0.0.1:8000"
169@@ -64,7 +72,7 @@
170 # From Address
171 deployment_settings.mail.sender = "'Sahana' <sahana@your.org>"
172 # Address to which mails get sent to approve new users
173-deployment_settings.mail.approver = "useradmin@your.org"
174+deployment_settings.mail.approver = "gravitatz@gmail.com"
175
176 # L10n settings
177 # Uncomment this if the deployment is just in a few countries
178@@ -254,7 +262,7 @@
179 pr_address = {"importer" : True},
180 pr_pe_contact = {"importer" : True},
181 pr_presence = {"importer" : True},
182- pr_identity = {"importer" : True},
183+ pr_identity = {"importer" : True},
184 pr_person = {"importer" : True},
185 pr_group = {"importer" : True},
186 pr_group_membership = {"importer" : True},
187@@ -327,18 +335,18 @@
188 # module_type = 10,
189 # ),
190 importer = Storage(
191- name_nice = "Spreadsheet Importer",
192- description = "Used to import data from spreadsheets into the database",
193- module_type = 10,
194+ name_nice = "Spreadsheet Importer",
195+ description = "Used to import data from spreadsheets into the database",
196+ module_type = 10,
197 ),
198 survey = Storage(
199- name_nice = "Survey Module",
200- description = "Create, enter, and manage surveys.",
201- module_type = 10,
202+ name_nice = "Survey Module",
203+ description = "Create, enter, and manage surveys.",
204+ module_type = 10,
205 )
206 #lms = Storage(
207 # name_nice = T("Logistics Management System"),
208 # description = T("An intake system, a warehouse management system, commodity tracking, supply chain management, procurement and other asset and resource management capabilities."),
209 # module_type = 10
210 # ),
211-)
212\ No newline at end of file
213+)
214
215=== modified file 'models/00_utils.py'
216--- models/00_utils.py 2010-10-04 21:57:29 +0000
217+++ models/00_utils.py 2010-10-11 14:11:40 +0000
218@@ -38,7 +38,7 @@
219 # Security Policy
220 #session.s3.self_registration = deployment_settings.get_security_self_registration()
221 session.s3.security_policy = deployment_settings.get_security_policy()
222-
223+
224 # We Audit if either the Global or Module asks us to
225 # (ignore gracefully if module author hasn't implemented this)
226 try:
227
228=== modified file 'models/01_menu.py'
229--- models/01_menu.py 2010-10-09 20:35:42 +0000
230+++ models/01_menu.py 2010-10-11 14:11:40 +0000
231@@ -91,6 +91,7 @@
232 [T("Messaging"), False, "#",[
233 [T("Global Messaging Settings"), False, URL(r=request, c="msg", f="setting", args=[1, "update"])],
234 [T("Email Settings"), False, URL(r=request, c="msg", f="email_settings", args=[1, "update"])],
235+ [T("Twitter Settings"), False, URL(r=request, c="msg", f="twitter_settings", args=[1, "update"])],
236 [T("Modem Settings"), False, URL(r=request, c="msg", f="modem_settings", args=[1, "update"])],
237 [T("Gateway Settings"), False, URL(r=request, c="msg", f="gateway_settings", args=[1, "update"])],
238 [T("Tropo Settings"), False, URL(r=request, c="msg", f="tropo_settings", args=[1, "update"])],
239
240=== modified file 'models/msg.py'
241--- models/msg.py 2010-10-10 20:14:10 +0000
242+++ models/msg.py 2010-10-11 14:11:40 +0000
243@@ -6,7 +6,6 @@
244
245 module = "msg"
246 if deployment_settings.has_module(module):
247-
248 # Settings
249 resource = "setting"
250 tablename = "%s_%s" % (module, resource)
251@@ -18,6 +17,53 @@
252 table.outgoing_sms_handler.requires = IS_IN_SET(["Modem","Gateway","Tropo"], zero=None)
253
254 #------------------------------------------------------------------------
255+ resource="twitter_settings"
256+ tablename = "%s_%s" % (module, resource)
257+ table = db.define_table(tablename,
258+ Field("pin"),
259+ Field("oauth_key"),
260+ Field("oauth_secret"),
261+ Field("twitter_account"),
262+ migrate=migrate)
263+ table.oauth_key.writable = False
264+ table.oauth_secret.writable = False
265+
266+ ### comment these 2 when debugging
267+ table.oauth_key.readable = False
268+ table.oauth_secret.readable = False
269+
270+ table.twitter_account.writable = False
271+
272+ def twitter_settings_onvalidation(form):
273+ """ Complete oauth: take tokens from session + pin from form, and do the 2nd API call to twitter """
274+ if form.vars.pin and session.s3.twitter_request_key and session.s3.twitter_request_secret:
275+ try:
276+ import tweepy
277+ except:
278+ raise HTTP(501,body="can't import tweepy")
279+
280+ oauth = tweepy.OAuthHandler(deployment_settings.oauth.consumer_key,
281+ deployment_settings.oauth.consumer_secret)
282+ oauth.set_request_token(session.s3.twitter_request_key,session.s3.twitter_request_secret)
283+ try:
284+ oauth.get_access_token(form.vars.pin)
285+ form.vars.oauth_key = oauth.access_token.key
286+ form.vars.oauth_secret = oauth.access_token.secret
287+ twitter = tweepy.API(oauth)
288+ form.vars.twitter_account = twitter.me().screen_name
289+ form.vars.pin = "" # we won't need it anymore
290+ return
291+ except tweepy.TweepError:
292+ session.error=T("Settings were reset because authenticating with twitter failed")
293+ # Either user asked to reset, or error - clear everything
294+ for k in ['oauth_key','oauth_secret','twitter_account']:
295+ form.vars[k] = ""
296+ for k in ['twitter_request_key','twitter_request_secret']:
297+ session.s3[k] = ""
298+
299+ s3xrc.model.configure(table, onvalidation=twitter_settings_onvalidation)
300+
301+ #------------------------------------------------------------------------
302 resource = "email_settings"
303 tablename = "%s_%s" % (module, resource)
304 table = db.define_table(tablename,
305
306=== modified file 'modules/s3cfg.py'
307--- modules/s3cfg.py 2010-09-21 06:34:46 +0000
308+++ modules/s3cfg.py 2010-10-11 14:11:40 +0000
309@@ -11,6 +11,7 @@
310 self.database = Storage()
311 self.gis = Storage()
312 self.mail = Storage()
313+ self.oauth = Storage()
314 self.L10n = Storage()
315 self.security = Storage()
316 self.ui = Storage()
317@@ -107,6 +108,12 @@
318 def get_gis_spatialdb(self):
319 return self.gis.get("spatialdb", False)
320
321+ # OAuth settings
322+ def get_oauth_consumer_key(self):
323+ return self.oauth.get("consumer_key","")
324+ def get_oauth_consumer_secret(self):
325+ return self.oauth.get("consumer_secret","")
326+
327 # L10N Settings
328 def get_L10n_countries(self):
329 return self.L10n.get("countries", "")