Commit 928cc9054b057b5b14ed07d6cb6020d6236e866d
1 parent
79e91d8c
Exists in
master
and in
1 other branch
Survey refactoring.
Showing
2 changed files
with
104 additions
and
126 deletions
Show diff stats
src/web/survey.py
@@ -8,6 +8,7 @@ import sys | @@ -8,6 +8,7 @@ import sys | ||
8 | import simplejson as json | 8 | import simplejson as json |
9 | import apt | 9 | import apt |
10 | import re | 10 | import re |
11 | +import socket | ||
11 | 12 | ||
12 | sys.path.insert(0,"../") | 13 | sys.path.insert(0,"../") |
13 | 14 | ||
@@ -15,6 +16,7 @@ import logging | @@ -15,6 +16,7 @@ import logging | ||
15 | from config import Config | 16 | from config import Config |
16 | from recommender import * | 17 | from recommender import * |
17 | from user import * | 18 | from user import * |
19 | +from data import DebianPackage | ||
18 | 20 | ||
19 | import urllib | 21 | import urllib |
20 | 22 | ||
@@ -77,64 +79,13 @@ class Package: | @@ -77,64 +79,13 @@ class Package: | ||
77 | subtags = [] | 79 | subtags = [] |
78 | return debtags | 80 | return debtags |
79 | 81 | ||
80 | -class Request: | ||
81 | - def __init__(self,web_input,submissions_dir,user_id=0,pkgs_list=0): | ||
82 | - self.strategy = "" | ||
83 | - if user_id: | ||
84 | - self.user_id = user_id | ||
85 | - self.outputdir = os.path.join(submissions_dir,user_id) | ||
86 | - logging.info("New round for user %s" % self.user_id) | ||
87 | - else: | ||
88 | - self.outputdir = tempfile.mkdtemp(prefix='',dir=submissions_dir) | ||
89 | - self.user_id = self.outputdir.lstrip(submissions_dir) | ||
90 | - logging.info("Request from user %s" % self.user_id) | ||
91 | - logging.debug("Created dir %s" % self.outputdir) | ||
92 | - | ||
93 | - pkgs_list_file = os.path.join(self.outputdir,"packages_list") | ||
94 | - if pkgs_list: | ||
95 | - self.pkgs_list = pkgs_list | ||
96 | - if not os.path.exists(pkgs_list_file): | ||
97 | - with open(pkgs_list_file,"w") as f: | ||
98 | - for pkg in pkgs_list: | ||
99 | - f.write(pkg+"\n") | ||
100 | - else: | ||
101 | - self.pkgs_list = [] | ||
102 | - if web_input['pkgs_file'].value: | ||
103 | - f = open(pkgs_list_file, "w") | ||
104 | - lines = web_input['pkgs_file'].file.readlines() | ||
105 | - with open(os.path.join(self.outputdir,"upload"), "w") as upload: | ||
106 | - upload.writelines(lines) | ||
107 | - # popcon submission format | ||
108 | - if lines[0].startswith('POPULARITY-CONTEST'): | ||
109 | - del lines[0] | ||
110 | - del lines[-1] | ||
111 | - package_name_field = 2 | ||
112 | - else: | ||
113 | - package_name_field = 0 | ||
114 | - for line in lines: | ||
115 | - self.pkgs_list.append(line.split()[package_name_field]) | ||
116 | - for pkg in self.pkgs_list: | ||
117 | - f.write(pkg+'\n') | ||
118 | - f.close() | ||
119 | - | ||
120 | - def __str__(self): | ||
121 | - return "Request %s:\n %s" % (self.user_id,str(self.pkgs_list)) | ||
122 | - | ||
123 | - def validates(self): | ||
124 | - self.errors = [] | ||
125 | - if not self.pkgs_list: | ||
126 | - self.errors.append("No packages list provided.") | ||
127 | - if self.errors: | ||
128 | - return False | ||
129 | - return True | ||
130 | - | ||
131 | class Save: | 82 | class Save: |
132 | def POST(self): | 83 | def POST(self): |
133 | web_input = web.input() | 84 | web_input = web.input() |
134 | logging.info("Saving user evaluation...") | 85 | logging.info("Saving user evaluation...") |
135 | logging.info(web_input) | 86 | logging.info(web_input) |
136 | user_id = web_input['user_id'].encode('utf8') | 87 | user_id = web_input['user_id'].encode('utf8') |
137 | - with open("./submissions/%s/packages_list" % user_id) as packages_list: | 88 | + with open("./submissions/%s/uploaded_file" % user_id) as packages_list: |
138 | pkgs_list = [line.strip() for line in packages_list.readlines()] | 89 | pkgs_list = [line.strip() for line in packages_list.readlines()] |
139 | strategy = web_input['strategy'] | 90 | strategy = web_input['strategy'] |
140 | logging.debug("Saving evaluation for user %s, strategy %s and packages..." | 91 | logging.debug("Saving evaluation for user %s, strategy %s and packages..." |
@@ -164,10 +115,48 @@ class Save: | @@ -164,10 +115,48 @@ class Save: | ||
164 | else: | 115 | else: |
165 | return render.survey_index() | 116 | return render.survey_index() |
166 | 117 | ||
118 | +class Request: | ||
119 | + def __init__(self,web_input,submissions_dir): | ||
120 | + self.strategy = "" | ||
121 | + # Check if it is first round | ||
122 | + if web_input.has_key('user_id'): | ||
123 | + self.user_id = web_input['user_id'].encode('utf8') | ||
124 | + self.user_dir = os.path.join(submissions_dir, self.user_id) | ||
125 | + logging.info("New round for user %s" % self.user_id) | ||
126 | + else: | ||
127 | + self.user_dir = tempfile.mkdtemp(prefix='',dir=submissions_dir) | ||
128 | + self.user_id = self.user_dir.split("/")[-1] | ||
129 | + logging.info("Request from user %s" % self.user_id) | ||
130 | + logging.debug("Created dir %s" % self.user_dir) | ||
131 | + uploaded_file = os.path.join(self.user_dir,"uploaded_file") | ||
132 | + if not os.path.exists(uploaded_file): | ||
133 | + if web_input['pkgs_file'].value: | ||
134 | + lines = web_input['pkgs_file'].file.readlines() | ||
135 | + with open(uploaded_file, "w") as uploaded: | ||
136 | + uploaded.writelines(lines) | ||
137 | + with open(uploaded_file) as uploaded: | ||
138 | + if uploaded.readline().startswith('POPULARITY-CONTEST'): | ||
139 | + self.user = PopconSystem(uploaded_file,self.user_id) | ||
140 | + else: | ||
141 | + self.user = PkgsListSystem(uploaded_file,self.user_id) | ||
142 | + | ||
143 | + def __str__(self): | ||
144 | + return "Request %s:\n %s" % (self.user.user_id, | ||
145 | + str(self.user.pkg_profile)) | ||
146 | + | ||
147 | + def validates(self): | ||
148 | + self.errors = [] | ||
149 | + if not self.user.pkg_profile: | ||
150 | + self.errors.append("No packages list provided.") | ||
151 | + if self.errors: | ||
152 | + return False | ||
153 | + return True | ||
154 | + | ||
167 | class Survey: | 155 | class Survey: |
168 | def __init__(self): | 156 | def __init__(self): |
169 | logging.info("Setting up survey...") | 157 | logging.info("Setting up survey...") |
170 | - self.rec = Recommender(Config()) | 158 | + self.cfg = Config() |
159 | + self.rec = Recommender(self.cfg) | ||
171 | self.submissions_dir = "./submissions/" | 160 | self.submissions_dir = "./submissions/" |
172 | if not os.path.exists(self.submissions_dir): | 161 | if not os.path.exists(self.submissions_dir): |
173 | os.makedirs(self.submissions_dir) | 162 | os.makedirs(self.submissions_dir) |
@@ -175,25 +164,12 @@ class Survey: | @@ -175,25 +164,12 @@ class Survey: | ||
175 | def POST(self): | 164 | def POST(self): |
176 | web_input = web.input(pkgs_file={}) | 165 | web_input = web.input(pkgs_file={}) |
177 | logging.debug("Survey web_input %s" % str(web_input)) | 166 | logging.debug("Survey web_input %s" % str(web_input)) |
178 | - self.strategies = ["cb","cbd","cbt","col"] | ||
179 | - # If it is not the first strategy round, save the previous evaluation | ||
180 | - if not web_input.has_key('user_id'): | ||
181 | - request = Request(web_input,self.submissions_dir) | ||
182 | - else: | ||
183 | - user_id = web_input['user_id'].encode('utf8') | ||
184 | - with open("./submissions/%s/packages_list" % user_id) as packages_list: | ||
185 | - pkgs_list = [line.strip() for line in packages_list.readlines()] | ||
186 | - request = Request(web_input,self.submissions_dir,user_id,pkgs_list) | 167 | + self.strategies = ["demo_cb","demo_cbd","demo_cbt","demo_col"]#,"demo_colco"] |
168 | + request = Request(web_input,self.submissions_dir) | ||
187 | if not request.validates(): | 169 | if not request.validates(): |
188 | return render.error_survey() | 170 | return render.error_survey() |
189 | else: | 171 | else: |
190 | - user = User(dict.fromkeys(request.pkgs_list,1),request.user_id) | ||
191 | - program_profile = user.filter_pkg_profile(os.path.join(self.rec.cfg.filters,"program")) | ||
192 | - desktop_profile = user.filter_pkg_profile(os.path.join(self.rec.cfg.filters,"desktop")) | ||
193 | - if (len(desktop_profile)>10 or | ||
194 | - len(desktop_profile)>len(program_profile)/2): | ||
195 | - self.strategies = [strategy_str+"_desktop" for strategy_str | ||
196 | - in self.strategies[:]] | 172 | + # Check the remaining strategies and select a new one |
197 | old_strategies = [dirs for root, dirs, files in | 173 | old_strategies = [dirs for root, dirs, files in |
198 | os.walk(os.path.join(self.submissions_dir, | 174 | os.walk(os.path.join(self.submissions_dir, |
199 | request.user_id))] | 175 | request.user_id))] |
@@ -203,34 +179,45 @@ class Survey: | @@ -203,34 +179,45 @@ class Survey: | ||
203 | else: | 179 | else: |
204 | strategies = self.strategies | 180 | strategies = self.strategies |
205 | if not strategies: | 181 | if not strategies: |
206 | - return render.thanks(user_id) | 182 | + return render.thanks(request.user_id) |
207 | request.strategy = random.choice(strategies) | 183 | request.strategy = random.choice(strategies) |
208 | logging.info("Selected \'%s\' from %s" % (request.strategy,strategies)) | 184 | logging.info("Selected \'%s\' from %s" % (request.strategy,strategies)) |
185 | + # Get recommendation | ||
209 | self.rec.set_strategy(request.strategy) | 186 | self.rec.set_strategy(request.strategy) |
210 | - prediction = self.rec.get_recommendation(user,10).get_prediction() | ||
211 | - logging.info("Prediction for user %s" % user.user_id) | 187 | + prediction = self.rec.get_recommendation(request.user,2).get_prediction() |
188 | + logging.info("Prediction for user %s" % request.user_id) | ||
212 | logging.info(str(prediction)) | 189 | logging.info(str(prediction)) |
213 | - output_dir = ("./submissions/%s/%s/" % | ||
214 | - (user.user_id,request.strategy)) | ||
215 | - os.makedirs(output_dir) | ||
216 | - with open(os.path.join(output_dir,"prediction"),"w") as prediction_file: | 190 | + strategy_dir = os.path.join(request.user_dir,request.strategy) |
191 | + os.makedirs(strategy_dir) | ||
192 | + with open(os.path.join(strategy_dir,"prediction"),"w") as prediction_file: | ||
217 | for pkg,rating in prediction: | 193 | for pkg,rating in prediction: |
218 | prediction_file.write("%s %f.2\n" % (pkg,rating)) | 194 | prediction_file.write("%s %f.2\n" % (pkg,rating)) |
219 | logging.debug("Saved %s/%s prediction to file" % | 195 | logging.debug("Saved %s/%s prediction to file" % |
220 | - (user.user_id,request.strategy)) | 196 | + (request.user_id,request.strategy)) |
221 | recommendation = [result[0] for result in prediction] | 197 | recommendation = [result[0] for result in prediction] |
222 | - pkg_summaries = {} | ||
223 | - pkg_details = [] | ||
224 | - cache = apt.Cache() | ||
225 | - for pkg in recommendation: | ||
226 | - try: | ||
227 | - logging.debug("Getting details of package %s" % pkg) | ||
228 | - pkg_details.append(Package().get_details_from_dde(pkg)) | ||
229 | - pkg_summaries[pkg] = cache[pkg].candidate.summary | ||
230 | - except: | ||
231 | - pkg_summaries[pkg] = "" | ||
232 | - if pkg_details: | ||
233 | - return render.survey(pkg_details, request) | 198 | + |
199 | + # Check connection to DDE | ||
200 | + try: | ||
201 | + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||
202 | + s.connect((self.cfg.dde_server,self.cfg.dde_port)) | ||
203 | + dde = 1 | ||
204 | + s.close() | ||
205 | + except: | ||
206 | + dde =0 | ||
207 | + logging.debug("Could not connect to dde") | ||
208 | + # Load packages details | ||
209 | + pkgs_details = [] | ||
210 | + for pkg_name in recommendation: | ||
211 | + logging.info("Getting details of package %s" % pkg_name) | ||
212 | + pkg = DebianPackage(pkg_name) | ||
213 | + if dde: | ||
214 | + pkg.load_details_from_dde(self.cfg.dde_server,self.cfg.dde_port) | ||
215 | + else: | ||
216 | + pkg.load_details_from_apt() | ||
217 | + pkgs_details.append(pkg) | ||
218 | + if pkgs_details: | ||
219 | + logging.info("Rendering survey slide...") | ||
220 | + return render.survey(pkgs_details, request) | ||
234 | else: | 221 | else: |
235 | return render.error_survey() | 222 | return render.error_survey() |
236 | 223 | ||
@@ -241,7 +228,7 @@ def add_global_hook(): | @@ -241,7 +228,7 @@ def add_global_hook(): | ||
241 | return handler() | 228 | return handler() |
242 | return _wrapper | 229 | return _wrapper |
243 | 230 | ||
244 | -render = web.template.render('templates/', base='layout') | 231 | +render = web.template.render('templates/', base='layout', globals={'hasattr':hasattr}) |
245 | render_plain = web.template.render('templates/') | 232 | render_plain = web.template.render('templates/') |
246 | 233 | ||
247 | urls = ('/', 'Index', | 234 | urls = ('/', 'Index', |
src/web/templates/survey.html
1 | -$def with (pkg_details, request) | 1 | +$def with (pkgs_details, request) |
2 | $var title: Survey | 2 | $var title: Survey |
3 | $var mod = 'survey'; | 3 | $var mod = 'survey'; |
4 | $var cssfiles: static/coda-slider-2.0/stylesheets/coda-slider-2.0.css static/css/facebox.css static/css/survey.css | 4 | $var cssfiles: static/coda-slider-2.0/stylesheets/coda-slider-2.0.css static/css/facebox.css static/css/survey.css |
@@ -38,7 +38,7 @@ button below. | @@ -38,7 +38,7 @@ button below. | ||
38 | 38 | ||
39 | <form action="/save" method="post" enctype="multipart/form-data" name="surveyform"> | 39 | <form action="/save" method="post" enctype="multipart/form-data" name="surveyform"> |
40 | 40 | ||
41 | -<input type="hidden" name="user_id" value=$request.user_id> | 41 | +<input type="hidden" name="user_id" value=$request.user.user_id> |
42 | <input type="hidden" name="strategy" value=$request.strategy> | 42 | <input type="hidden" name="strategy" value=$request.strategy> |
43 | <div id="controls-form" style="display: none;" class="show-end"><!-- display show in the end form --> | 43 | <div id="controls-form" style="display: none;" class="show-end"><!-- display show in the end form --> |
44 | <label for="finish_button" id="tip-finish"> | 44 | <label for="finish_button" id="tip-finish"> |
@@ -57,63 +57,54 @@ button below. | @@ -57,63 +57,54 @@ button below. | ||
57 | 57 | ||
58 | <div class="coda-slider-wrapper hide-end"> | 58 | <div class="coda-slider-wrapper hide-end"> |
59 | <div class="coda-slider preload" id="coda-slider-1"> | 59 | <div class="coda-slider preload" id="coda-slider-1"> |
60 | -$for pkg in pkg_details: | 60 | +$for pkg in pkgs_details: |
61 | <div class="panel"> | 61 | <div class="panel"> |
62 | <div class="panel-wrapper"> | 62 | <div class="panel-wrapper"> |
63 | <div class="screenshot"> | 63 | <div class="screenshot"> |
64 | <a class="link-thumb" rel="facebox" | 64 | <a class="link-thumb" rel="facebox" |
65 | - href="http://screenshots.debian.net/screenshot/$pkg['package']?.jpg" | ||
66 | - title="Click to enlarge screenshot of package $pkg['package']" alt="Click to enlarge screenshot"> | ||
67 | - <img height="70px" src="http://screenshots.debian.net/thumbnail/$pkg['package']" | ||
68 | - alt="Screenshot $pkg['package']" /></a> | 65 | + href="http://screenshots.debian.net/screenshot/$pkg.name?.jpg" |
66 | + title="Click to enlarge screenshot of package $pkg.name" alt="Click to enlarge screenshot"> | ||
67 | + <img height="70px" src="http://screenshots.debian.net/thumbnail/$pkg.name" | ||
68 | + alt="Screenshot $pkg.name" /></a> | ||
69 | </div><!-- screenshot --> | 69 | </div><!-- screenshot --> |
70 | - <h1 style="float: right;">($(pkg_details.index(pkg)+1)/10)</h1> | ||
71 | - <h1 id="title_pkg"> $pkg['package'] <br /> | ||
72 | - <span>$pkg['description']</span></h1> | 70 | + <h1 style="float: right;">($(pkgs_details.index(pkg)+1)/10)</h1> |
71 | + <h1 id="title_pkg"> $pkg.name <br /> | ||
72 | + <span>$pkg.summary</span></h1> | ||
73 | <br style="clear: both;" /> | 73 | <br style="clear: both;" /> |
74 | <div id="panel-controls" class="glass"> | 74 | <div id="panel-controls" class="glass"> |
75 | <fieldset> | 75 | <fieldset> |
76 | <legend>How do you evaluate this<br> recommendation?</legend> | 76 | <legend>How do you evaluate this<br> recommendation?</legend> |
77 | <label class="radioButton"> | 77 | <label class="radioButton"> |
78 | - <input class="radio" type="radio" name="evaluation-$pkg_details.index(pkg)" value="surprising" /> | 78 | + <input class="radio" type="radio" name="evaluation-$pkgs_details.index(pkg)" value="surprising" /> |
79 | Pleasantly surprising | 79 | Pleasantly surprising |
80 | - <!--<div class="tip tip"> | ||
81 | - <p>Pleasantly $pkg['package'] FIXME </p> | ||
82 | - </div>--> | ||
83 | </label><br /> | 80 | </label><br /> |
84 | <label class="radioButton"> | 81 | <label class="radioButton"> |
85 | - <input class="radio yesb" type="radio" name="evaluation-$pkg_details.index(pkg)" value="good" /> | 82 | + <input class="radio yesb" type="radio" name="evaluation-$pkgs_details.index(pkg)" value="good" /> |
86 | Useful | 83 | Useful |
87 | - <!--<div class="tip tip"> | ||
88 | - <p>Good $pkg['package'] FIXME </p> | ||
89 | - </div>--> | ||
90 | </label><br /> | 84 | </label><br /> |
91 | <label class="radioButton"> | 85 | <label class="radioButton"> |
92 | - <input class="radio" type="radio" name="evaluation-$pkg_details.index(pkg)" value="poor" /> | 86 | + <input class="radio" type="radio" name="evaluation-$(pkgs_details.index(pkg))" value="poor" /> |
93 | Poor | 87 | Poor |
94 | - <!--<div class="tip tip"> | ||
95 | - <p>Poor $pkg['package'] FIXME </p> | ||
96 | - </div>--> | ||
97 | </label> | 88 | </label> |
98 | </fieldset> | 89 | </fieldset> |
99 | <br style="clear: both;" /> | 90 | <br style="clear: both;" /> |
100 | </div><!-- #panel-controls --> | 91 | </div><!-- #panel-controls --> |
101 | <div class="content-pkg"> | 92 | <div class="content-pkg"> |
102 | <ul> | 93 | <ul> |
103 | - <li><b>Description</b>: | ||
104 | - <br />$:pkg['long_description']</li> | ||
105 | - $if pkg['homepage']: | ||
106 | - <li><b>Homepage</b>: $pkg['homepage']</li> | ||
107 | - $if pkg['task']: | ||
108 | - <li><b>Tasks</b>: $pkg['task']</li> | ||
109 | - <li><b>Section</b>: $pkg['section']</li> | ||
110 | - $if pkg['recommends']: | ||
111 | - <li><b>Recommends</b>: $pkg['recommends']</li> | ||
112 | - $if pkg['suggests']: | ||
113 | - <li><b>Suggests</b>: $pkg['suggests']</li> | ||
114 | - $if pkg['origin']: | ||
115 | - <li><b>Origin</b>: $pkg['origin']</li> | ||
116 | - <li><b>Maintainer</b>: $pkg['maintainer']</li> | 94 | + $if hasattr(pkg,'description'): |
95 | + <li><b>Description</b>: <br />$:pkg.description</li> | ||
96 | + $if hasattr(pkg,'homepage'): | ||
97 | + <li><b>Homepage</b>: $pkg.homepage</li> | ||
98 | + $if hasattr(pkg,'task'): | ||
99 | + <li><b>Tasks</b>: $pkg.task</li> | ||
100 | + $if hasattr(pkg,'section'): | ||
101 | + <li><b>Section</b>: $pkg.section</li> | ||
102 | + $if hasattr(pkg,'recommends'): | ||
103 | + <li><b>Recommends</b>: $pkg.recommends</li> | ||
104 | + $if hasattr(pkg,'suggests'): | ||
105 | + <li><b>Suggests</b>: $pkg.suggests</li> | ||
106 | + $if hasattr(pkg,'maintainer'): | ||
107 | + <li><b>Maintainer</b>: $pkg.maintainer.</li> | ||
117 | </ul> | 108 | </ul> |
118 | </div><!-- id="content-pkg" --> | 109 | </div><!-- id="content-pkg" --> |
119 | </div><!-- .panel-wrapper --> | 110 | </div><!-- .panel-wrapper --> |