| 1 |
#!/usr/bin/python
|
| 2 |
#
|
| 3 |
# db.py -- Front end
|
| 4 |
#
|
| 5 |
|
| 6 |
|
| 7 |
#
|
| 8 |
# externally provided modules
|
| 9 |
#
|
| 10 |
|
| 11 |
#import pgdb; DBAPI = pgdb
|
| 12 |
from pyPgSQL import PgSQL; DBAPI = PgSQL
|
| 13 |
|
| 14 |
from mod_python import apache, util
|
| 15 |
from htmltmpl import TemplateManager, TemplateProcessor
|
| 16 |
import os
|
| 17 |
import pwd
|
| 18 |
import urllib
|
| 19 |
import cgi
|
| 20 |
from types import *
|
| 21 |
import time
|
| 22 |
import mimetypes
|
| 23 |
|
| 24 |
#
|
| 25 |
# own modules
|
| 26 |
#
|
| 27 |
from HWDButils import *
|
| 28 |
|
| 29 |
#
|
| 30 |
# HWDB classes
|
| 31 |
#
|
| 32 |
import HWDB
|
| 33 |
|
| 34 |
def URLfromMapping(d):
|
| 35 |
"returns usual relative URL with 'parameters' from mapping d"
|
| 36 |
return "db.py?" + urllib.urlencode(d)
|
| 37 |
|
| 38 |
def indentationListFromTree(t, level = 0):
|
| 39 |
"""Returns list of tuples (string, indent_level) from mapping coded tree.
|
| 40 |
Items of one level are sorted.
|
| 41 |
"""
|
| 42 |
result = []
|
| 43 |
keys = t.keys()
|
| 44 |
keys.sort()
|
| 45 |
for i in keys:
|
| 46 |
result.append((i, level))
|
| 47 |
result.extend(indentationListFromTree(t[i], level + 1))
|
| 48 |
return result
|
| 49 |
|
| 50 |
def error(tp, message):
|
| 51 |
"""Report error in TemplateProcessor.
|
| 52 |
Sets "err_switch" and "err_message" in TemplateProcessor tp
|
| 53 |
"""
|
| 54 |
tp.set("err_switch", 1)
|
| 55 |
tp.set("err_message", message)
|
| 56 |
|
| 57 |
def message(tp, message):
|
| 58 |
"""Report state (of successful transaction)
|
| 59 |
Sets "message" in TemplateProcessor tp
|
| 60 |
"""
|
| 61 |
tp.set("message", message)
|
| 62 |
|
| 63 |
class Page:
|
| 64 |
"""Abstract Page
|
| 65 |
Derived classes must define:
|
| 66 |
fillTemplate(self, tp) with tp == TemplateProcessor
|
| 67 |
"""
|
| 68 |
def __init__(self, req, args):
|
| 69 |
self.req = req
|
| 70 |
self.args = args
|
| 71 |
self.db = HWDB.DB()
|
| 72 |
|
| 73 |
def put(self):
|
| 74 |
"""called by web server entry point function (handler())
|
| 75 |
returns apache.OK on success
|
| 76 |
"""
|
| 77 |
self.req.content_type = "text/html"
|
| 78 |
self.req.send_http_header()
|
| 79 |
|
| 80 |
template = TemplateManager().prepare(HWDB.WEBDIR + "/index.html")
|
| 81 |
tp = TemplateProcessor()
|
| 82 |
self.req.write(tp.process(template, 1))
|
| 83 |
self.fillTemplate(tp)
|
| 84 |
self.req.write(tp.process(template))
|
| 85 |
return apache.OK
|
| 86 |
|
| 87 |
def getArgsDict(self):
|
| 88 |
"returns page arguments (GET/POST) as dictionary"
|
| 89 |
result = {}
|
| 90 |
for i in self.args.keys():
|
| 91 |
result[i] = self.args[i]
|
| 92 |
return result
|
| 93 |
|
| 94 |
class MainPage(Page):
|
| 95 |
def fillTemplate(self, tp):
|
| 96 |
tp.set("switch_main", 1)
|
| 97 |
tp.set("subpage", "")
|
| 98 |
|
| 99 |
class SubPage(Page):
|
| 100 |
"""Abstract Page utilizing the main template to include another one
|
| 101 |
with variable name "subpage".
|
| 102 |
|
| 103 |
Derived classes need to define:
|
| 104 |
getTemplateName() == string with filename
|
| 105 |
fillSubTemplate(self, tp) == template generation
|
| 106 |
"""
|
| 107 |
def getEntityName(self):
|
| 108 |
"returns string name of requested entity"
|
| 109 |
if self.args.has_key("entity"):
|
| 110 |
return self.args["entity"]
|
| 111 |
else:
|
| 112 |
return "category"
|
| 113 |
|
| 114 |
def getEntityClass(self):
|
| 115 |
"returns class of requested entity"
|
| 116 |
return HWDB.getEntityClass(self.getEntityName())
|
| 117 |
|
| 118 |
def fillTemplate(self, tp):
|
| 119 |
template2 = TemplateManager().prepare(self.getTemplateName())
|
| 120 |
tp2 = TemplateProcessor()
|
| 121 |
|
| 122 |
tp2.set(self.getEntityName()[0:3] + "_switch", 1)
|
| 123 |
|
| 124 |
self.fillSubTemplate(tp2)
|
| 125 |
tp.set("subpage", tp2.process(template2))
|
| 126 |
|
| 127 |
class AboutPage(SubPage):
|
| 128 |
def getTemplateName(self):
|
| 129 |
return HWDB.WEBDIR + "/about.html"
|
| 130 |
|
| 131 |
def fillSubTemplate(self, tp):
|
| 132 |
pass
|
| 133 |
|
| 134 |
def HTML_ul_tree(d):
|
| 135 |
result = ""
|
| 136 |
keys = d.keys()
|
| 137 |
if len(keys) > 0:
|
| 138 |
keys.sort()
|
| 139 |
result += "<ul>\n"
|
| 140 |
for i in keys:
|
| 141 |
result += "<li>"
|
| 142 |
a = {"action": "browse", "entity": "device", "category": i}
|
| 143 |
result += ('<a href="' + URLfromMapping(a) + '">' +
|
| 144 |
cgi.escape(i, 1) + '</a>\n')
|
| 145 |
a = {"action": "view", "entity": "category", "name": i}
|
| 146 |
result += ('(<a href="' + URLfromMapping(a) +
|
| 147 |
'">View</a>)\n')
|
| 148 |
result += "</li>"
|
| 149 |
result += HTML_ul_tree(d[i])
|
| 150 |
result += "</ul>\n"
|
| 151 |
return result
|
| 152 |
|
| 153 |
# default: 20
|
| 154 |
LISTSIZE=20 #3
|
| 155 |
|
| 156 |
class BrowsePage(SubPage):
|
| 157 |
"""
|
| 158 |
entity=
|
| 159 |
"category" (default)
|
| 160 |
"device"
|
| 161 |
...
|
| 162 |
"""
|
| 163 |
def getTemplateName(self):
|
| 164 |
return HWDB.WEBDIR + "/browse.html"
|
| 165 |
|
| 166 |
def getPageList(self, count, offset):
|
| 167 |
result = []
|
| 168 |
count = (count - 1) / LISTSIZE + 1
|
| 169 |
if count <= 1:
|
| 170 |
return result
|
| 171 |
offset /= LISTSIZE
|
| 172 |
if offset >= count:
|
| 173 |
offset = count - 1
|
| 174 |
if offset < 0:
|
| 175 |
offset = 0
|
| 176 |
# "previous"
|
| 177 |
if offset > 0:
|
| 178 |
d = self.getArgsDict()
|
| 179 |
d["offset"] = (offset - 1) * LISTSIZE
|
| 180 |
result.append({"label": "<< previous", "link": URLfromMapping(d)})
|
| 181 |
# +/- 10 pages
|
| 182 |
for i in range(-10, 10, 1):
|
| 183 |
if offset + i >= 0 and offset + i < count:
|
| 184 |
d = self.getArgsDict()
|
| 185 |
d["offset"] = (offset + i) * LISTSIZE
|
| 186 |
result.append(
|
| 187 |
{"label": offset + i + 1, "link": URLfromMapping(d)})
|
| 188 |
# "next"
|
| 189 |
if offset < count - 1:
|
| 190 |
d = self.getArgsDict()
|
| 191 |
d["offset"] = (offset + 1) * LISTSIZE
|
| 192 |
result.append({"label": "next >>", "link": URLfromMapping(d)})
|
| 193 |
return result
|
| 194 |
|
| 195 |
def getQueryAttrs(self):
|
| 196 |
"returns mapping from attribute names to queried values"
|
| 197 |
result = {}
|
| 198 |
for i in HWDB.getColumnNames(self.getEntityClass()):
|
| 199 |
if self.args.has_key(i) and self.args[i] != "":
|
| 200 |
result[i] = self.args[i]
|
| 201 |
return result
|
| 202 |
|
| 203 |
def getQueryStrategies(self):
|
| 204 |
"returns mapping from attribute names to strategies (HWDB.STRATEGY_*)"
|
| 205 |
result = {}
|
| 206 |
for i in HWDB.getColumnNames(self.getEntityClass()):
|
| 207 |
key = "strategy_" + i
|
| 208 |
if self.args.has_key(key):
|
| 209 |
if self.args[key] == "exact":
|
| 210 |
result[i] = HWDB.STRATEGY_EXACT
|
| 211 |
elif self.args[key] == "substring":
|
| 212 |
result[i] = HWDB.STRATEGY_SUBSTRING
|
| 213 |
else:
|
| 214 |
raise Error("Unknown strategy: " + self.args[key])
|
| 215 |
return result
|
| 216 |
|
| 217 |
def fillSubTemplate(self, tp):
|
| 218 |
if self.args.has_key("offset"):
|
| 219 |
offset = int(self.args["offset"])
|
| 220 |
else:
|
| 221 |
offset = 0
|
| 222 |
if offset < 0:
|
| 223 |
offset = 0
|
| 224 |
|
| 225 |
entity = self.getEntityName()
|
| 226 |
if entity == "category":
|
| 227 |
#
|
| 228 |
# Browse Categories
|
| 229 |
#
|
| 230 |
d = self.db.getCategoryTree()
|
| 231 |
cat_list = HTML_ul_tree(d["Hardware"])
|
| 232 |
if cat_list == "":
|
| 233 |
cat_list = "[No categories found.]"
|
| 234 |
tp.set("cat_list", cat_list)
|
| 235 |
|
| 236 |
else:
|
| 237 |
if (entity == "device" or entity == "manufacturer" or
|
| 238 |
entity == "capability" or entity == "driver"):
|
| 239 |
limit = LISTSIZE
|
| 240 |
count = self.db.query(
|
| 241 |
HWDB.getEntityClass(entity), {}, count = 1)
|
| 242 |
tp.set("Page_list", self.getPageList(count, offset))
|
| 243 |
tp.set("page_num", offset / LISTSIZE + 1)
|
| 244 |
tp.set("page_max", (count - 1) / LISTSIZE + 1)
|
| 245 |
else:
|
| 246 |
limit = 0;
|
| 247 |
result = self.db.query(HWDB.getEntityClass(entity),
|
| 248 |
attrs = self.getQueryAttrs(),
|
| 249 |
strategies = self.getQueryStrategies(),
|
| 250 |
limit = limit, offset = offset, ordered = 1)
|
| 251 |
|
| 252 |
if entity == "capability":
|
| 253 |
#
|
| 254 |
# Browse Capabilities
|
| 255 |
#
|
| 256 |
cap_list = []
|
| 257 |
for i in range(len(result)):
|
| 258 |
cap_list.append({"no": offset + i + 1,
|
| 259 |
"name": result[i].getName(),
|
| 260 |
"description": result[i].getDescription(),
|
| 261 |
"view_link": URLfromMapping(
|
| 262 |
{"action": "view",
|
| 263 |
"entity": "capability",
|
| 264 |
"name": result[i].getName()})})
|
| 265 |
tp.set("Cap_list", cap_list)
|
| 266 |
|
| 267 |
elif entity == "manufacturer":
|
| 268 |
#
|
| 269 |
# Browse Manufacturers
|
| 270 |
#
|
| 271 |
man_list = []
|
| 272 |
for i in range(len(result)):
|
| 273 |
man_list.append({"no": offset + i + 1,
|
| 274 |
"shortname": result[i].getShortName(),
|
| 275 |
"longname": result[i].getLongName(),
|
| 276 |
"view_link": URLfromMapping(
|
| 277 |
{"action": "view",
|
| 278 |
"entity": "manufacturer",
|
| 279 |
"shortname": result[i].getShortName()})})
|
| 280 |
tp.set("Man_list", man_list)
|
| 281 |
|
| 282 |
elif entity == "device":
|
| 283 |
#
|
| 284 |
# Browse Devices
|
| 285 |
#
|
| 286 |
dev_list = []
|
| 287 |
for i in range(len(result)):
|
| 288 |
dev_list.append({"no": offset + i + 1,
|
| 289 |
"manufacturer": result[i].getManufacturerShortName(),
|
| 290 |
"model": result[i].getModel(),
|
| 291 |
"category": result[i].getCategoryName(),
|
| 292 |
"view_link": URLfromMapping(
|
| 293 |
{"action": "view",
|
| 294 |
"entity": "device",
|
| 295 |
"manufacturer":
|
| 296 |
result[i].getManufacturerShortName(),
|
| 297 |
"model": result[i].getModel()}),
|
| 298 |
"view_manufacturer": URLfromMapping(
|
| 299 |
{"action": "view",
|
| 300 |
"entity": "manufacturer",
|
| 301 |
"shortname":
|
| 302 |
result[i].getManufacturerShortName()}),
|
| 303 |
"view_category": URLfromMapping(
|
| 304 |
{"action": "view",
|
| 305 |
"entity": "category",
|
| 306 |
"name": result[i].getCategoryName()}),
|
| 307 |
"report_num": result[i].getNumberOfReports()})
|
| 308 |
tp.set("Dev_list", dev_list)
|
| 309 |
|
| 310 |
elif entity == "architecture":
|
| 311 |
#
|
| 312 |
# Browse Architectures
|
| 313 |
#
|
| 314 |
arc_list = []
|
| 315 |
for i in range(len(result)):
|
| 316 |
arc_list.append({"no": offset + i + 1,
|
| 317 |
"name": result[i].getName(),
|
| 318 |
"description": result[i].getDescription(),
|
| 319 |
"view_link": URLfromMapping(
|
| 320 |
{"action": "view",
|
| 321 |
"entity": "architecture",
|
| 322 |
"name": result[i].getName()})})
|
| 323 |
tp.set("Arc_list", arc_list)
|
| 324 |
|
| 325 |
elif entity == "driver":
|
| 326 |
#
|
| 327 |
# Browse Drivers
|
| 328 |
#
|
| 329 |
dri_list = []
|
| 330 |
for i in range(len(result)):
|
| 331 |
non_free = intFromBoolean(result[i].getNonFree())
|
| 332 |
dri_list.append({"no": offset + i + 1,
|
| 333 |
"name": result[i].getName(),
|
| 334 |
"version": result[i].getVersion(),
|
| 335 |
"non_free": non_free,
|
| 336 |
"view_link": URLfromMapping(
|
| 337 |
{"action": "view",
|
| 338 |
"entity": "driver",
|
| 339 |
"name": result[i].getName(),
|
| 340 |
"version": result[i].getVersion()})})
|
| 341 |
tp.set("Dri_list", dri_list)
|
| 342 |
|
| 343 |
elif entity == "release":
|
| 344 |
#
|
| 345 |
# Browse Releases
|
| 346 |
#
|
| 347 |
rel_list = []
|
| 348 |
for i in range(len(result)):
|
| 349 |
rel_list.append({"no": offset + i + 1,
|
| 350 |
"version": result[i].getVersion(),
|
| 351 |
"codename": result[i].getCodename(),
|
| 352 |
"released": result[i].getReleased(),
|
| 353 |
"view_link": URLfromMapping(
|
| 354 |
{"action": "view",
|
| 355 |
"entity": "release",
|
| 356 |
"version": result[i].getVersion()})})
|
| 357 |
tp.set("Rel_list", rel_list)
|
| 358 |
|
| 359 |
else:
|
| 360 |
error(tp, "Unknown entity type.")
|
| 361 |
|
| 362 |
class SearchPage(SubPage):
|
| 363 |
def getTemplateName(self):
|
| 364 |
return HWDB.WEBDIR + "/search.html"
|
| 365 |
|
| 366 |
def fillSubTemplate(self, tp):
|
| 367 |
pass
|
| 368 |
|
| 369 |
class ReportPage(SubPage):
|
| 370 |
def getTemplateName(self):
|
| 371 |
return HWDB.WEBDIR + "/report.html"
|
| 372 |
|
| 373 |
def fillSubTemplate(self, tp):
|
| 374 |
pass
|
| 375 |
|
| 376 |
class LoginPage(SubPage):
|
| 377 |
def getTemplateName(self):
|
| 378 |
return HWDB.WEBDIR + "/login.html"
|
| 379 |
|
| 380 |
def fillSubTemplate(self, tp):
|
| 381 |
pass
|
| 382 |
|
| 383 |
class InputPage(SubPage):
|
| 384 |
"""Abstract Input Page.
|
| 385 |
Derived classes have to define fillForm(tp) with tp == TemplateProcessor
|
| 386 |
"""
|
| 387 |
def getTemplateName(self):
|
| 388 |
return HWDB.WEBDIR + "/edit.html"
|
| 389 |
|
| 390 |
def fillSubTemplate(self, tp):
|
| 391 |
self.fillForm(tp)
|
| 392 |
#
|
| 393 |
# Set values for individual entities
|
| 394 |
#
|
| 395 |
if self.getEntityName() == "category":
|
| 396 |
selected = None
|
| 397 |
if self.args.has_key("name"):
|
| 398 |
result = self.db.query(HWDB.Category,
|
| 399 |
{"name": self.args["name"]})
|
| 400 |
if len(result) > 0:
|
| 401 |
selected = result[0].getParentName()
|
| 402 |
self.setCategoryList(tp, "parent", selected = selected)
|
| 403 |
elif self.getEntityName() == "device":
|
| 404 |
selected = None
|
| 405 |
if self.args.has_key("manufacturer") and self.args.has_key("model"):
|
| 406 |
result = self.db.query(HWDB.Device,
|
| 407 |
{"manufacturer": self.args["manufacturer"],
|
| 408 |
"model": self.args["model"]})
|
| 409 |
if len(result) > 0:
|
| 410 |
selected = result[0].getCategoryName()
|
| 411 |
self.setCategoryList(tp, "category", selected = selected,
|
| 412 |
subtree = "Hardware")
|
| 413 |
|
| 414 |
try:
|
| 415 |
hidden_entity = '<input type="hidden" name="entity" value="'
|
| 416 |
hidden_entity += cgi.escape(self.getEntityName()) + '">\n'
|
| 417 |
tp.set("hidden_entity", hidden_entity)
|
| 418 |
except KeyError, e:
|
| 419 |
error(tp, "Incomplete request. Argument missing: " + str(e))
|
| 420 |
|
| 421 |
def setCategoryList(self, tp, attr_name, selected = None, subtree = None):
|
| 422 |
"""Init a category list in "new_" + attr_name (this is both the name
|
| 423 |
in the html form as well as the template variable name)
|
| 424 |
|
| 425 |
tp = TemplateProcessor
|
| 426 |
attr_name = attribute name to set in TemplateProcessor
|
| 427 |
selected = preselected item (string);
|
| 428 |
defaults to None, i.e. no preselection
|
| 429 |
subtree = name (string) of subtree to generate list from,
|
| 430 |
defaults to None, which means whole tree
|
| 431 |
"""
|
| 432 |
code = '<select name="new_' + attr_name + '" size="1">\n'
|
| 433 |
try:
|
| 434 |
category_tree = self.db.getCategoryTree()
|
| 435 |
except DBAPI.DatabaseError, e:
|
| 436 |
category_tree = {}
|
| 437 |
if subtree and category_tree.has_key(subtree):
|
| 438 |
category_tree = category_tree[subtree]
|
| 439 |
categories = indentationListFromTree(category_tree)
|
| 440 |
for i in categories:
|
| 441 |
code += ' <option value="' + cgi.escape(i[0], 1) + '"'
|
| 442 |
if i[0] == selected:
|
| 443 |
code += " selected"
|
| 444 |
code += '>'
|
| 445 |
code += " " * i[1] + cgi.escape(i[0], 1)
|
| 446 |
code += '</option>\n'
|
| 447 |
code += '</select>\n'
|
| 448 |
tp.set("new_" + attr_name, code)
|
| 449 |
|
| 450 |
class AddPage(InputPage):
|
| 451 |
def fillForm(self, tp):
|
| 452 |
tp.set("edit_switch", 0)
|
| 453 |
tp.set("action_name", "Add")
|
| 454 |
if self.getEntityName() == "driver":
|
| 455 |
tp.set("priority", 50)
|
| 456 |
elif self.getEntityName() == "picture":
|
| 457 |
tp.set("manufacturer", self.args["manufacturer"])
|
| 458 |
tp.set("model", self.args["model"])
|
| 459 |
elif self.getEntityName() == "report":
|
| 460 |
tp.set("manufacturer", self.args["manufacturer"])
|
| 461 |
tp.set("model", self.args["model"])
|
| 462 |
tp.set("certified_community", 1)
|
| 463 |
|
| 464 |
class EditPage(InputPage):
|
| 465 |
def fillForm(self, tp):
|
| 466 |
tp.set("edit_switch", 1)
|
| 467 |
tp.set("action_name", "Edit")
|
| 468 |
|
| 469 |
try:
|
| 470 |
entity = HWDB.getEntityClass(self.getEntityName())
|
| 471 |
pk = HWDB.getPrimaryKey(entity)
|
| 472 |
attrs = {}
|
| 473 |
for i in pk:
|
| 474 |
attrs[i] = self.args[i]
|
| 475 |
object = self.db.query(entity, attrs)[0]
|
| 476 |
keys = HWDB.getColumnNames(entity)
|
| 477 |
for i in keys:
|
| 478 |
tp.set(i, str(object.get(i)))
|
| 479 |
hidden_pk = ""
|
| 480 |
for i in pk:
|
| 481 |
hidden_pk += '<input type="hidden" name="' + i
|
| 482 |
hidden_pk += '" value="' + cgi.escape(object.get(i), 1)
|
| 483 |
hidden_pk += '">\n'
|
| 484 |
tp.set("hidden_pk", hidden_pk)
|
| 485 |
# Set values for individual entities
|
| 486 |
if self.getEntityName() == "driver":
|
| 487 |
tp.set("non_free", intFromBoolean(object.getNonFree()))
|
| 488 |
elif self.getEntityName() == "device":
|
| 489 |
original = object.getOriginal()
|
| 490 |
if original:
|
| 491 |
tp.set("original_manufacturer",
|
| 492 |
original.getManufacturerShortName())
|
| 493 |
tp.set("original_model", original.getModel())
|
| 494 |
elif self.getEntityName() == "picture":
|
| 495 |
tp.set("default_picture",
|
| 496 |
intFromBoolean(object.getDefaultPicture()))
|
| 497 |
elif self.getEntityName() == "report":
|
| 498 |
if object.getCertified() == "community":
|
| 499 |
tp.set("certified_community", 1)
|
| 500 |
elif object.getCertified() == "manufacturer":
|
| 501 |
tp.set("certified_manufacturer", 1)
|
| 502 |
elif object.getCertified() == "developer":
|
| 503 |
tp.set("certified_developer", 1)
|
| 504 |
except Error, e:
|
| 505 |
error(tp, "Edit error: " + str(e))
|
| 506 |
except KeyError, e:
|
| 507 |
error(tp, "Argument missing: " + str(e))
|
| 508 |
except IndexError, e:
|
| 509 |
error(tp, "Object not found: " + str(e))
|
| 510 |
except DBAPI.DatabaseError, e:
|
| 511 |
error(tp, "Database Error: " + str(e))
|
| 512 |
|
| 513 |
class AddSubmitPage(SubPage):
|
| 514 |
def getTemplateName(self):
|
| 515 |
return HWDB.WEBDIR + "/editsubmit.html"
|
| 516 |
|
| 517 |
def fillSubTemplate(self, tp):
|
| 518 |
tp.set("edit_switch", 0)
|
| 519 |
try:
|
| 520 |
#
|
| 521 |
# individual creation of entities due to entity constructors
|
| 522 |
#
|
| 523 |
if self.getEntityName() == "category":
|
| 524 |
if self.args["new_name"] != self.args["new_parent"]:
|
| 525 |
new_object = HWDB.Category(self.db, self.args["new_name"],
|
| 526 |
parent = self.args["new_parent"],
|
| 527 |
description = self.args["new_description"],
|
| 528 |
commit = 0)
|
| 529 |
else:
|
| 530 |
raise Error("Bad parent.")
|
| 531 |
elif self.getEntityName() == "capability":
|
| 532 |
new_object = HWDB.Capability(self.db, self.args["new_name"],
|
| 533 |
description = self.args["new_description"], commit = 0)
|
| 534 |
elif self.getEntityName() == "manufacturer":
|
| 535 |
shortname = self.args["new_shortname"]
|
| 536 |
longname = self.args["new_longname"]
|
| 537 |
if longname == "":
|
| 538 |
longname = shortname
|
| 539 |
new_object = HWDB.Manufacturer(self.db, shortname,
|
| 540 |
longname = longname,
|
| 541 |
description = self.args["new_description"],
|
| 542 |
url = self.args["new_url"],
|
| 543 |
contact = self.args["new_contact"], commit = 0)
|
| 544 |
elif self.getEntityName() == "device":
|
| 545 |
new_object = HWDB.Device(self.db,
|
| 546 |
self.args["new_manufacturer"],
|
| 547 |
self.args["new_model"],
|
| 548 |
category = self.args["new_category"],
|
| 549 |
url = self.args["new_url"],
|
| 550 |
description = self.args["new_description"],
|
| 551 |
commit = 0)
|
| 552 |
if (self.args["new_original_manufacturer"] != "" and
|
| 553 |
self.args["new_original_model"] != ""):
|
| 554 |
original = self.db.query(HWDB.Device, attrs = {
|
| 555 |
"manufacturer":
|
| 556 |
self.args["new_original_manufacturer"],
|
| 557 |
"model": self.args["new_original_model"]})[0]
|
| 558 |
new_object.setOriginal(original, commit = 0)
|
| 559 |
elif self.getEntityName() == "picture":
|
| 560 |
if (mimetypes.guess_type(self.args["new_filename"].filename)[0]
|
| 561 |
== None):
|
| 562 |
raise Error("Bad file name or MIME type.")
|
| 563 |
new_object = HWDB.Picture(self.db,
|
| 564 |
self.args["new_filename"].filename,
|
| 565 |
device = self.db.query(HWDB.Device, attrs = {
|
| 566 |
"manufacturer": self.args["new_manufacturer"],
|
| 567 |
"model": self.args["new_model"]})[0],
|
| 568 |
default_picture = self.args["new_default_picture"],
|
| 569 |
comment = self.args["new_comment"],
|
| 570 |
data = self.args["new_filename"].value,
|
| 571 |
commit = 0)
|
| 572 |
if new_object.getDefaultPicture():
|
| 573 |
# maintain default picture integrity
|
| 574 |
new_object.setDefaultPicture(1);
|
| 575 |
elif self.getEntityName() == "report":
|
| 576 |
new_object = HWDB.Report(self.db,
|
| 577 |
self.args["new_changed_by"],
|
| 578 |
device = self.db.query(HWDB.Device, attrs = {
|
| 579 |
"manufacturer": self.args["new_manufacturer"],
|
| 580 |
"model": self.args["new_model"]})[0],
|
| 581 |
certified = self.args["new_certified"],
|
| 582 |
comment = self.args["new_comment"],
|
| 583 |
url = self.args["new_url"],
|
| 584 |
commit = 0)
|
| 585 |
elif self.getEntityName() == "architecture":
|
| 586 |
new_object = HWDB.Architecture(self.db, self.args["new_name"],
|
| 587 |
description = self.args["new_description"],
|
| 588 |
commit = 0)
|
| 589 |
elif self.getEntityName() == "driver":
|
| 590 |
new_object = HWDB.Driver(self.db,
|
| 591 |
self.args["new_name"],
|
| 592 |
self.args["new_version"],
|
| 593 |
non_free = self.args["new_non_free"],
|
| 594 |
description = self.args["new_description"],
|
| 595 |
url = self.args["new_url"],
|
| 596 |
priority = self.args["new_priority"],
|
| 597 |
commit = 0)
|
| 598 |
elif self.getEntityName() == "release":
|
| 599 |
new_object = HWDB.Release(self.db,
|
| 600 |
self.args["new_version"],
|
| 601 |
codename = self.args["new_codename"],
|
| 602 |
released = self.args["new_released"],
|
| 603 |
commit = 0)
|
| 604 |
elif self.getEntityName() == "dbdata":
|
| 605 |
new_object = HWDB.DBData(self.db,
|
| 606 |
self.args["new_version"],
|
| 607 |
created = self.args["new_created"],
|
| 608 |
commit = 0)
|
| 609 |
except Error, e:
|
| 610 |
error(tp, "Couldn't add item: " + str(e))
|
| 611 |
self.db.rollback()
|
| 612 |
except KeyError, e:
|
| 613 |
error(tp, "Argument missing: " + str(e))
|
| 614 |
self.db.rollback()
|
| 615 |
except DBAPI.DatabaseError, e:
|
| 616 |
error(tp, "New item NOT accepted: " + str(e))
|
| 617 |
self.db.rollback()
|
| 618 |
except IndexError, e:
|
| 619 |
error(tp, "Object not found: " + str(e))
|
| 620 |
self.db.rollback()
|
| 621 |
else:
|
| 622 |
self.db.commit()
|
| 623 |
d = new_object.getPrimaryKeyAttrs()
|
| 624 |
d["action"] = "view"
|
| 625 |
d["entity"] = self.getEntityName()
|
| 626 |
message(tp, "<strong>New item ACCEPTED.</strong><br><br><br><br>" +
|
| 627 |
'<a href="' + URLfromMapping(d) +
|
| 628 |
'">View new entry</a>')
|
| 629 |
|
| 630 |
class EditSubmitPage(SubPage):
|
| 631 |
def getTemplateName(self):
|
| 632 |
return HWDB.WEBDIR + "/editsubmit.html"
|
| 633 |
|
| 634 |
def fillSubTemplate(self, tp):
|
| 635 |
tp.set("edit_switch", 1)
|
| 636 |
try:
|
| 637 |
entity = HWDB.getEntityClass(self.getEntityName())
|
| 638 |
keys = HWDB.getPrimaryKey(entity)
|
| 639 |
args = {}
|
| 640 |
for i in keys:
|
| 641 |
args[i] = self.args[i]
|
| 642 |
except KeyError, e:
|
| 643 |
error(tp, "Invalid argument: " + str(e))
|
| 644 |
else:
|
| 645 |
if self.args.has_key("delete"):
|
| 646 |
try:
|
| 647 |
self.db.delete(entity, args, commit = 1)
|
| 648 |
except DBAPI.DatabaseError, e:
|
| 649 |
error(tp, "Couldn't delete object from database. " +
|
| 650 |
"(Not present? Or referenced?)")
|
| 651 |
else:
|
| 652 |
message(tp, "Object successfully removed.")
|
| 653 |
else: # Update, not delete
|
| 654 |
try:
|
| 655 |
object = self.db.query(entity, args)[0]
|
| 656 |
|
| 657 |
update = {}
|
| 658 |
for i in HWDB.getColumnNames(entity):
|
| 659 |
if (self.args.has_key("new_" + i) and
|
| 660 |
self.args["new_" + i] != str(object.get(i))):
|
| 661 |
update[i] = self.args["new_" + i]
|
| 662 |
|
| 663 |
#
|
| 664 |
# Handle individual entity properties before update ...
|
| 665 |
#
|
| 666 |
if (self.getEntityName() == "device" or
|
| 667 |
self.getEntityName() == "report"):
|
| 668 |
# update last change date
|
| 669 |
t = time.localtime(time.time())
|
| 670 |
changed = DBAPI.Timestamp(
|
| 671 |
t[0], t[1], t[2], t[3], t[4], t[5])
|
| 672 |
update["changed"] = str(changed)
|
| 673 |
elif self.getEntityName() == "manufacturer":
|
| 674 |
# set long name to short name if former is empty
|
| 675 |
if update.has_key("shortname") and (
|
| 676 |
update.has_key("longname") and
|
| 677 |
update["longname"] == "" or
|
| 678 |
not update.has_key("longname") and
|
| 679 |
object.getLongName() == ""):
|
| 680 |
update["longname"] = update["shortname"]
|
| 681 |
elif self.getEntityName() == "picture":
|
| 682 |
# fix picture filename and data, to be updated
|
| 683 |
# "manually" after main update
|
| 684 |
if (update.has_key("filename") and
|
| 685 |
update["filename"].filename == ""):
|
| 686 |
del update["filename"]
|
| 687 |
if update.has_key("filename"):
|
| 688 |
picture_data = update["filename"].value
|
| 689 |
update["filename"] = update["filename"].filename
|
| 690 |
if (mimetypes.guess_type(
|
| 691 |
update["filename"])[0] == None):
|
| 692 |
raise Error("Bad file name or MIME type.")
|
| 693 |
else:
|
| 694 |
picture_data = None
|
| 695 |
|
| 696 |
#
|
| 697 |
# The update itself
|
| 698 |
#
|
| 699 |
if len(update):
|
| 700 |
object.update(update, commit = 0)
|
| 701 |
else:
|
| 702 |
raise Error("Nothing changed.")
|
| 703 |
|
| 704 |
#
|
| 705 |
# Handle individual entity properties after update ...
|
| 706 |
#
|
| 707 |
if self.getEntityName() == "category":
|
| 708 |
if self.db.integrityCheckCategory() != None:
|
| 709 |
self.db.rollback()
|
| 710 |
raise Error("Change would destroy tree integrity.")
|
| 711 |
if self.getEntityName() == "device":
|
| 712 |
if (self.args["new_original_manufacturer"] != "" and
|
| 713 |
self.args["new_original_model"] != ""):
|
| 714 |
original = self.db.query(HWDB.Device, attrs = {
|
| 715 |
"manufacturer":
|
| 716 |
self.args["new_original_manufacturer"],
|
| 717 |
"model": self.args["new_original_model"]})[0]
|
| 718 |
object.setOriginal(original)
|
| 719 |
else: # delete original
|
| 720 |
object.deleteOriginal()
|
| 721 |
if self.getEntityName() == "picture":
|
| 722 |
if picture_data:
|
| 723 |
object.setData(picture_data)
|
| 724 |
if (update.has_key("default_picture") and
|
| 725 |
object.getDefaultPicture()):
|
| 726 |
object.setDefaultPicture(1) # maintain integrity
|
| 727 |
|
| 728 |
except DBAPI.DatabaseError, e:
|
| 729 |
error(tp, "Changes NOT accepted: " + str(e))
|
| 730 |
self.db.rollback()
|
| 731 |
except IndexError, e:
|
| 732 |
error(tp, "Object not found: " + str(e))
|
| 733 |
self.db.rollback()
|
| 734 |
except Error, e:
|
| 735 |
error(tp, "Error on Change: " + str(e))
|
| 736 |
self.db.rollback()
|
| 737 |
else:
|
| 738 |
self.db.commit()
|
| 739 |
d = object.getPrimaryKeyAttrs()
|
| 740 |
d["action"] = "view"
|
| 741 |
d["entity"] = self.getEntityName()
|
| 742 |
message(tp, "<strong>Changes ACCEPTED.</strong>\n" +
|
| 743 |
"<br><br><br><br>\n" +
|
| 744 |
'<a href="' + URLfromMapping(d) + '">View entry</a>\n')
|
| 745 |
|
| 746 |
class ViewPage(SubPage):
|
| 747 |
def getTemplateName(self):
|
| 748 |
return HWDB.WEBDIR + "/view.html"
|
| 749 |
|
| 750 |
def fillSubTemplate(self, tp):
|
| 751 |
try:
|
| 752 |
entity = HWDB.getEntityClass(self.getEntityName())
|
| 753 |
attrs = {}
|
| 754 |
pk = HWDB.getPrimaryKey(entity)
|
| 755 |
for i in pk:
|
| 756 |
attrs[i] = self.args[i]
|
| 757 |
object = self.db.query(entity, attrs)[0]
|
| 758 |
attrs = object.getAttrs()
|
| 759 |
for i in attrs.keys():
|
| 760 |
tp.set(i, str(attrs[i]))
|
| 761 |
# handle special cases for entities w/ special needs
|
| 762 |
if self.getEntityName() == "device":
|
| 763 |
tp.set("view_manufacturer", URLfromMapping(
|
| 764 |
{"action": "view",
|
| 765 |
"entity": "manufacturer",
|
| 766 |
"shortname": object.getManufacturerShortName()}))
|
| 767 |
tp.set("view_category", URLfromMapping(
|
| 768 |
{"action": "view",
|
| 769 |
"entity": "category",
|
| 770 |
"name": object.getCategoryName()}))
|
| 771 |
original = object.getOriginal()
|
| 772 |
if original:
|
| 773 |
tp.set("view_original", URLfromMapping(
|
| 774 |
{"action": "view",
|
| 775 |
"entity": "device",
|
| 776 |
"manufacturer":
|
| 777 |
original.getManufacturerShortName(),
|
| 778 |
"model": original.getModel()}))
|
| 779 |
tp.set("original_switch", 1)
|
| 780 |
tp.set("original_manufacturer",
|
| 781 |
original.getManufacturerShortName())
|
| 782 |
tp.set("original_model", original.getModel())
|
| 783 |
tp.set("link_add_picture", URLfromMapping(
|
| 784 |
{"action": "add", "entity": "picture",
|
| 785 |
"manufacturer": object.getManufacturerShortName(),
|
| 786 |
"model": object.getModel()}))
|
| 787 |
tp.set("link_add_report", URLfromMapping(
|
| 788 |
{"action": "add", "entity": "report",
|
| 789 |
"manufacturer": object.getManufacturerShortName(),
|
| 790 |
"model": object.getModel()}))
|
| 791 |
|
| 792 |
pl = object.getPictures()
|
| 793 |
pictures_loop = []
|
| 794 |
for i in pl:
|
| 795 |
linkname = i.getFilename()
|
| 796 |
if not linkname:
|
| 797 |
linkname = "[empty filename]"
|
| 798 |
link_picture = URLfromMapping(
|
| 799 |
{"action": "picture",
|
| 800 |
"filename": i.getFilename(),
|
| 801 |
"manufacturer": i.getManufacturerShortName(),
|
| 802 |
"model": i.getModel()})
|
| 803 |
pictures_loop.append(
|
| 804 |
{"filename": linkname,
|
| 805 |
"link_picture": link_picture,
|
| 806 |
"link_view_picture": URLfromMapping(
|
| 807 |
{"action": "view",
|
| 808 |
"entity": "picture",
|
| 809 |
"filename": i.getFilename(),
|
| 810 |
"manufacturer": i.getManufacturerShortName(),
|
| 811 |
"model": i.getModel()}),
|
| 812 |
"default_picture":
|
| 813 |
intFromBoolean(i.getDefaultPicture())})
|
| 814 |
if i.getDefaultPicture():
|
| 815 |
tp.set("picture_switch", 1)
|
| 816 |
tp.set("link_picture", link_picture)
|
| 817 |
tp.set("Pictures_loop", pictures_loop)
|
| 818 |
|
| 819 |
rl = object.getReports()
|
| 820 |
reports_loop = []
|
| 821 |
for i in rl:
|
| 822 |
linkname = i.getChangedBy()
|
| 823 |
if not linkname:
|
| 824 |
linkname = "[no name specified]"
|
| 825 |
reports_loop.append(
|
| 826 |
{"changed_by": linkname,
|
| 827 |
"link_report": URLfromMapping(
|
| 828 |
{"action": "view",
|
| 829 |
"entity": "report",
|
| 830 |
"changed_by": i.getChangedBy(),
|
| 831 |
"manufacturer": i.getManufacturerShortName(),
|
| 832 |
"model": i.getModel()})})
|
| 833 |
tp.set("Reports_loop", reports_loop)
|
| 834 |
elif self.getEntityName() == "driver":
|
| 835 |
tp.set("non_free", intFromBoolean(object.getNonFree()))
|
| 836 |
elif self.getEntityName() == "picture":
|
| 837 |
tp.set("link_picture", URLfromMapping(
|
| 838 |
{"action": "picture",
|
| 839 |
"filename": object.getFilename(),
|
| 840 |
"manufacturer":
|
| 841 |
object.getManufacturerShortName(),
|
| 842 |
"model": object.getModel()}))
|
| 843 |
tp.set("view_manufacturer", URLfromMapping(
|
| 844 |
{"action": "view",
|
| 845 |
"entity": "manufacturer",
|
| 846 |
"shortname": object.getManufacturerShortName()}))
|
| 847 |
tp.set("view_device", URLfromMapping(
|
| 848 |
{"action": "view",
|
| 849 |
"entity": "device",
|
| 850 |
"manufacturer":
|
| 851 |
object.getManufacturerShortName(),
|
| 852 |
"model": object.getModel()}))
|
| 853 |
tp.set("default_picture",
|
| 854 |
intFromBoolean(object.getDefaultPicture()))
|
| 855 |
elif self.getEntityName() == "report":
|
| 856 |
tp.set("view_manufacturer", URLfromMapping(
|
| 857 |
{"action": "view",
|
| 858 |
"entity": "manufacturer",
|
| 859 |
"shortname": object.getManufacturerShortName()}))
|
| 860 |
tp.set("view_device", URLfromMapping(
|
| 861 |
{"action": "view",
|
| 862 |
"entity": "device",
|
| 863 |
"manufacturer":
|
| 864 |
object.getManufacturerShortName(),
|
| 865 |
"model": object.getModel()}))
|
| 866 |
except Error, e:
|
| 867 |
error(tp, "Error: " + str(e))
|
| 868 |
except IndexError, e:
|
| 869 |
error(tp, "Object not found: " + str(e))
|
| 870 |
except KeyError, e:
|
| 871 |
error(tp, "Bad argument: " + str(e))
|
| 872 |
except DBAPI.DatabaseError, e:
|
| 873 |
error(tp, "Item not found: " + str(e))
|
| 874 |
else:
|
| 875 |
d = object.getPrimaryKeyAttrs()
|
| 876 |
d["action"] = "edit"
|
| 877 |
d["entity"] = self.getEntityName()
|
| 878 |
message(tp,'<a href="' + URLfromMapping(d) + '">Edit entry</a>')
|
| 879 |
|
| 880 |
class Picture(Page):
|
| 881 |
"No HTML page but an image (data of class Picture)"
|
| 882 |
def put(self):
|
| 883 |
if (self.args.has_key("filename") and self.args.has_key("manufacturer")
|
| 884 |
and self.args.has_key("model")):
|
| 885 |
picture = self.db.query(HWDB.Picture,
|
| 886 |
{"filename": self.args["filename"],
|
| 887 |
"manufacturer": self.args["manufacturer"],
|
| 888 |
"model": self.args["model"]})[0]
|
| 889 |
self.req.content_type = picture.getContentType()
|
| 890 |
self.req.send_http_header()
|
| 891 |
|
| 892 |
self.req.write(picture.getData())
|
| 893 |
return apache.OK
|
| 894 |
else:
|
| 895 |
return apache.HTTP_NOT_FOUND
|
| 896 |
|
| 897 |
#
|
| 898 |
# Allowed actions
|
| 899 |
#
|
| 900 |
actions = {"main": MainPage,
|
| 901 |
"about": AboutPage,
|
| 902 |
"browse": BrowsePage,
|
| 903 |
"search": SearchPage,
|
| 904 |
"report": ReportPage,
|
| 905 |
"login": LoginPage,
|
| 906 |
|
| 907 |
"add": AddPage,
|
| 908 |
"addsubmit": AddSubmitPage,
|
| 909 |
"edit": EditPage,
|
| 910 |
"editsubmit": EditSubmitPage,
|
| 911 |
"view": ViewPage,
|
| 912 |
"picture": Picture}
|
| 913 |
|
| 914 |
#
|
| 915 |
# Entry point from web server
|
| 916 |
#
|
| 917 |
def handler(req):
|
| 918 |
global actions
|
| 919 |
|
| 920 |
args = util.FieldStorage(req, 1)
|
| 921 |
if args.has_key("action"):
|
| 922 |
if actions.has_key(args["action"]):
|
| 923 |
return actions[args["action"]](req, args).put()
|
| 924 |
else:
|
| 925 |
return apache.HTTP_FORBIDDEN
|
| 926 |
else:
|
| 927 |
return MainPage(req, args).put()
|
| 928 |
|