~nmu-sscheel/gtg/rework-task-editor

« back to all changes in this revision

Viewing changes to GTG/plugins/import_json/import_json.py

  • Committer: Bertrand Rousseau
  • Date: 2012-05-09 22:33:25 UTC
  • mfrom: (1178 trunk)
  • mto: This revision was merged to the branch mainline in revision 1179.
  • Revision ID: bertrand.rousseau@gmail.com-20120509223325-a53d8nwo0x9g93bc
Merge nimit branch and trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- coding: utf-8 -*-
2
 
# Copyright (c) 2010 - Bryce Harrington <bryce@canonical.com>
3
 
#
4
 
# This program is free software: you can redistribute it and/or modify it under
5
 
# the terms of the GNU General Public License as published by the Free Software
6
 
# Foundation, either version 3 of the License, or (at your option) any later
7
 
# version.
8
 
#
9
 
# This program is distributed in the hope that it will be useful, but WITHOUT
10
 
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
 
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12
 
# details.
13
 
#
14
 
# You should have received a copy of the GNU General Public License along with
15
 
# this program.  If not, see <http://www.gnu.org/licenses/>.
16
 
 
17
 
# This plugin was built for a specific purpose and is not a general-purpose or
18
 
# full-featured JSON importer.
19
 
#
20
 
# It imports JSON files with the following syntax.
21
 
#
22
 
# There just be a top-level key named "specs", with key names of your choosing.
23
 
# Each sub sub-hash must have a "details_url" or "url" key, whose values
24
 
# becomes part of the description of every item in the "work_items" array.
25
 
# There is no way to set any other description, nor it is possible to import
26
 
# tags, or dates.
27
 
#
28
 
# Only items with a "status" of "todo" are imported, the rest are skipped.
29
 
 
30
 
# The software will first scan the file to find all the "assignee" values in the file
31
 
# And then pop-up a dialog as you to choose an username. It then imports only the TODO
32
 
# items for those usernames. The username is not actually imported.
33
 
 
34
 
# {
35
 
#  "specs": {
36
 
#   "my-spec": {
37
 
#    "details_url": "http://www.gnome.org/",
38
 
#    "work_items": [
39
 
#     {
40
 
#      "assignee": "john-doe",
41
 
#      "description": "Do something",
42
 
#      "spec": "my-spec",
43
 
#      "status": "todo"
44
 
#     },
45
 
#     ...
46
 
#    ]
47
 
#   },
48
 
#   "another-spec": {
49
 
#   ...
50
 
#   },
51
 
#   ...
52
 
#  },
53
 
# }
54
 
 
55
 
import gtk
56
 
import os
57
 
import re
58
 
import urllib2
59
 
 
60
 
# Choose simplejson or json by which is available
61
 
try:
62
 
    import simplejson as json
63
 
except ImportError:
64
 
    import json
65
 
 
66
 
from GTG.tools.readurl import readurl
67
 
 
68
 
class pluginImportJson:
69
 
    
70
 
    def __init__(self):
71
 
        self.plugin_api = None
72
 
 
73
 
        self.menu_item = gtk.MenuItem("Import from _JSON")
74
 
        self.menu_item.connect('activate', self.on_import_json_activate)
75
 
        
76
 
        self.tb_button = gtk.ToolButton(gtk.STOCK_INFO)
77
 
        self.tb_button.set_label("Import from JSON")
78
 
        self.tb_button.connect('clicked', self.on_import_json_activate)
79
 
        self.separator = gtk.SeparatorToolItem()
80
 
 
81
 
        self.dialog = None
82
 
        self.txtImport = None
83
 
        self.json_tasks = None
84
 
 
85
 
        self.dialog_select_username = None
86
 
        self.select_username = None
87
 
        self.usernames = []
88
 
 
89
 
    def activate(self, plugin_api):
90
 
        self.plugin_api = plugin_api
91
 
        self.plugin_api.add_menu_item(self.menu_item)
92
 
        self.plugin_api.add_toolbar_item(self.separator)
93
 
        self.plugin_api.add_toolbar_item(self.tb_button)
94
 
 
95
 
    def onTaskClosed(self, plugin_api):
96
 
        pass
97
 
        
98
 
    def onTaskOpened(self, plugin_api):
99
 
        pass
100
 
        
101
 
    def deactivate(self, plugin_api):
102
 
        plugin_api.remove_menu_item(self.menu_item)
103
 
        plugin_api.remove_toolbar_item(self.tb_button)
104
 
        plugin_api.remove_toolbar_item(self.separator)
105
 
        self.txtImport = None
106
 
 
107
 
    def loadDialog(self):
108
 
        self.builder = gtk.Builder()
109
 
        self.builder.add_from_file(os.path.join(
110
 
                os.path.dirname(os.path.abspath(__file__)) + \
111
 
                    "/import_json.ui"))
112
 
 
113
 
        self.dialog = self.builder.get_object("dlg_import_json")
114
 
        if not self.dialog:
115
 
            return
116
 
        self.txtImport = self.builder.get_object("txt_import")
117
 
 
118
 
        self.dialog.connect("delete_event", self.close_dialog)
119
 
        self.dialog.connect("response", self.on_response)
120
 
        
121
 
        self.dialog.show_all()
122
 
 
123
 
    def loadDialogSelectUsername(self):
124
 
        path = os.path.dirname(os.path.abspath(__file__))
125
 
 
126
 
        self.dialog_select_username = self.builder.get_object("dlg_select_username")
127
 
        if not self.dialog_select_username or len(self.usernames) < 1:
128
 
            return
129
 
        self.dialog_select_username.set_title("Select username")
130
 
        self.dialog_select_username.set_transient_for(self.dialog)
131
 
        self.dialog_select_username.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
132
 
        # TODO:  Handle ok and cancel buttons
133
 
        self.dialog_select_username.connect("response", self.on_response_select_username)
134
 
        self.dialog_select_username.connect("delete_event", self.close_dialog_select_username)
135
 
 
136
 
        username_model = gtk.ListStore(str)
137
 
        self.select_username = self.builder.get_object("select_username")
138
 
        self.select_username.set_model(username_model)
139
 
        for u in self.usernames:
140
 
            self.select_username.append_text(u)
141
 
        self.select_username.set_active(0)
142
 
 
143
 
        self.dialog_select_username.show_all()
144
 
 
145
 
    def print_selected(self, widget, data=None):
146
 
        print self.select_username.get_active()
147
 
 
148
 
    def close_dialog(self, widget, data=None):
149
 
        self.dialog.destroy()
150
 
        return True    
151
 
    
152
 
    def close_dialog_select_username(self, widget, data=None):
153
 
        self.dialog_select_username.destroy()
154
 
        return True    
155
 
    
156
 
    # plugin features
157
 
    def on_import_json_activate(self, widget):
158
 
        self.loadDialog()
159
 
 
160
 
    def on_response(self, widget, response_id):
161
 
        if response_id == -7 or response_id == -4:
162
 
            self.close_dialog(widget)
163
 
        elif response_id == 0 and self.txtImport:
164
 
            self.import_json(widget)
165
 
        else:
166
 
            print "Error:  Unknown response id %d" %(response_id)
167
 
 
168
 
    def on_response_select_username(self, widget, response_id):
169
 
        if response_id == -7:
170
 
            self.dialog.show_all()
171
 
            self.close_dialog_select_username(widget)
172
 
        elif response_id == -4:
173
 
            self.close_dialog_select_username(widget)
174
 
        elif response_id == 0:
175
 
            self.import_tasks(widget)
176
 
            self.close_dialog_select_username(widget)
177
 
        else:
178
 
            print "Error:  Unknown response id %d" %(response_id)
179
 
        return response_id
180
 
 
181
 
    def import_json(self, widget):
182
 
        url = self.txtImport.get_text()
183
 
        json_text = readurl(url)
184
 
        if not json_text:
185
 
            # TODO:  Pop up error dialog
186
 
            print "Error: Could not load url %s" % url
187
 
            return
188
 
 
189
 
        # Convert to json
190
 
        self.json_tasks = json.loads(json_text)
191
 
 
192
 
        # TODO:  Create listing of usernames available
193
 
        self.usernames = [ ]
194
 
        for specname,spec in self.json_tasks['specs'].items():
195
 
            for wi in spec['work_items']:
196
 
                if wi['status'] != "todo":
197
 
                    continue
198
 
                if wi['assignee'] in self.usernames:
199
 
                    continue
200
 
                if not wi['assignee']:
201
 
                    continue
202
 
                self.usernames.append(wi['assignee'])
203
 
        self.usernames.sort()
204
 
 
205
 
        # Pop up dialog allowing user to select username
206
 
        self.loadDialogSelectUsername()
207
 
        self.dialog.hide_all()
208
 
        self.dialog_select_username.run()
209
 
 
210
 
    def import_tasks(self, widget):
211
 
        username = self.usernames[self.select_username.get_active()]
212
 
        re_dehtml = re.compile(r'<.*?>')
213
 
 
214
 
        for specname,spec in self.json_tasks['specs'].items():
215
 
            for wi in spec['work_items']:
216
 
                if wi['assignee'] != username:
217
 
                    continue
218
 
                if wi['status'] != 'todo':
219
 
                    continue
220
 
 
221
 
                text = ""
222
 
                if spec['details_url']:
223
 
                    text = spec['details_url']
224
 
                elif spec['url']:
225
 
                    text = spec['url']
226
 
                task = self.plugin_api.get_requester().new_task(pid=None, tags=None, newtask=True)
227
 
                task.set_title(re_dehtml.sub('', wi['description']))
228
 
                task.set_text(re_dehtml.sub('', text))
229
 
                task.sync()
230
 
                # TODO:  Do something with spec['priority']
231
 
 
232
 
        self.close_dialog_select_username(widget)
233
 
        self.close_dialog(widget)