def renderManageExtensions(req, db, user): cursor = db.cursor() what = page.utils.getParameter(req, "what", "available") selected_versions = page.utils.json_decode(page.utils.getParameter(req, "select", "{}")) focused = page.utils.getParameter(req, "focus", None) if what == "available": title = "Available Extensions" other = ("installed extensions", "/manageextensions?what=installed" + ("&user="******"")) listed_extensions = Extension.find() elif what == "installed": title = "Installed Extensions" other = ("available extensions", "/manageextensions?what=available" + ("&user="******"")) cursor.execute("""SELECT DISTINCT users.name, extensions.name FROM users JOIN extensions ON (extensions.author=users.id) JOIN extensionversions ON (extensionversions.extension=extensions.id) LEFT OUTER JOIN extensionroles_page ON (extensionroles_page.version=extensionversions.id AND extensionroles_page.uid=%s) LEFT OUTER JOIN extensionroles_processcommits ON (extensionroles_processcommits.version=extensionversions.id AND extensionroles_processcommits.uid=%s) WHERE extensionroles_page.uid IS NOT NULL OR extensionroles_processcommits.uid IS NOT NULL""", (user.id, user.id)) listed_extensions = [Extension(*row) for row in cursor] req.content_type = "text/html; charset=utf-8" document = htmlutils.Document(req) document.setTitle("Manage Extensions") html = document.html() head = html.head() body = html.body() def generateRight(target): target.a("button", href="tutorial?item=extensions").text("Tutorial") target.text(" ") target.a("button", href="tutorial?item=extensions-api").text("API Documentation") page.utils.generateHeader(body, db, user, current_page="extensions", generate_right=generateRight) document.addExternalStylesheet("resource/manageextensions.css") document.addExternalScript("resource/manageextensions.js") document.addInternalScript(user.getJS()) table = page.utils.PaleYellowTable(body, title) table.titleRight.a(href=other[1]).text("[" + other[0] + "]") for extension in listed_extensions: extension_path = extension.getPath() author = dbutils.User.fromName(db, extension.getAuthorName()) if focused and extension.getKey() != focused: continue selected_version = selected_versions.get(extension.getKey(), False) installed_sha1, installed_version = extension.getInstalledVersion(db, user) if selected_version is False: selected_version = installed_version if selected_version is None: install_version = "live" elif selected_version is not False: install_version = "version/%s" % selected_version else: install_version = None try: if selected_version is False: manifest = extension.readManifest() else: manifest = extension.getInstallationStatus(db, user, selected_version) except ManifestError, error: manifest = None if installed_sha1: current_sha1 = extension.getCurrentSHA1(installed_version) if manifest: if what == "available" and author != user and manifest.hidden: continue else: if author != user: continue if manifest: buttons = [] if installed_version is False: if install_version: buttons.append(("Install", "installExtension(%s, %s, %s)" % (htmlutils.jsify(extension.getAuthorName()), htmlutils.jsify(extension.getName()), htmlutils.jsify(install_version)))) else: buttons.append(("Uninstall", "uninstallExtension(%s, %s)" % (htmlutils.jsify(extension.getAuthorName()), htmlutils.jsify(extension.getName())))) if installed_sha1 and installed_sha1 != current_sha1: label = "Update" elif manifest.status != "installed": label = "Reinstall" else: label = None if label: buttons.append((label, "reinstallExtension(%s, %s, %s)" % (htmlutils.jsify(extension.getAuthorName()), htmlutils.jsify(extension.getName()), htmlutils.jsify(install_version)))) else: buttons = None def renderItem(target): span = target.span("name") span.b().text(extension.getName()) span.text(" by %s" % author.fullname) span = target.span("details") span.b().text("Details: ") select = span.select("details", critic_author=extension.getAuthorName(), critic_extension=extension.getName()) select.option(value='', selected="selected" if selected_version is False else None).text("Select version") versions = extension.getVersions() if versions: optgroup = select.optgroup(label="Official Versions") for version in extension.getVersions(): optgroup.option(value="version/%s" % version, selected="selected" if selected_version == version else None).text("%s" % version.upper()) optgroup = select.optgroup(label="Development") optgroup.option(value='live', selected="selected" if selected_version is None else None).text("LIVE") if manifest: is_installed = manifest.status in ("partial", "installed") or installed_version is not False if is_installed: target.span("installed").text(" [installed]") target.div("description").preformatted().text(manifest.description, linkify=True) else: is_installed = False target.div("description broken").preformatted().a(href="loadmanifest?author=%s&name=%s" % (extension.getAuthorName(), extension.getName())).text("[This extension has an invalid MANIFEST file]") if selected_version is False: return pages = [] injects = [] processcommits = [] processchanges = [] scheduled = [] if manifest: for role in manifest.roles: if isinstance(role, PageRole): pages.append(role) elif isinstance(role, InjectRole): injects.append(role) elif isinstance(role, ProcessCommitsRole): processcommits.append(role) elif isinstance(role, ProcessChangesRole): processchanges.append(role) elif isinstance(role, ScheduledRole): scheduled.append(role) role_table = target.table("roles") if pages: role_table.tr().th(colspan=2).text("Pages") for role in pages: row = role_table.tr() url = "%s/%s" % (dbutils.getURLPrefix(db), role.pattern) if is_installed and role.installed and "*" not in url: row.td("pattern").a(href=url).text(url) else: row.td("pattern").text(url) td = row.td("description") td.text(role.description) if is_installed and not role.installed: td.text(" ") td.span("inactive").text("[Not active!]") if injects: role_table.tr().th(colspan=2).text("Page Injections") for role in injects: row = role_table.tr() row.td("pattern").text("%s/%s" % (dbutils.getURLPrefix(db), role.pattern)) td = row.td("description") td.text(role.description) if is_installed and not role.installed: td.text(" ") td.span("inactive").text("[Not active!]") if processcommits: role_table.tr().th(colspan=2).text("ProcessCommits hooks") ul = role_table.tr().td(colspan=2).ul() for role in processcommits: li = ul.li() li.text(role.description) if is_installed and not role.installed: li.text(" ") li.span("inactive").text("[Not active!]") if processchanges: role_table.tr().th(colspan=2).text("ProcessChanges hooks") ul = role_table.tr().td(colspan=2).ul() for role in processchanges: li = ul.li() li.text(role.description) if is_installed and not role.installed: li.text(" ") li.span("inactive").text("[Not active!]") if scheduled: role_table.tr().th(colspan=2).text("Scheduled hooks") for role in scheduled: row = role_table.tr() row.td("pattern").text("%s @ %s" % (role.frequency, role.at)) td = row.td("description") td.text(role.description) if is_installed and not role.installed: td.text(" ") td.span("inactive").text("[Not active!]") cursor.execute("""SELECT DISTINCT uid FROM extensionroles JOIN extensionversions ON (extensionversions.id=extensionroles.version) JOIN extensions ON (extensions.id=extensionversions.extension) WHERE extensions.author=%s AND extensions.name=%s""", (author.id, extension.getName())) installed_count = len(cursor.fetchall()) if installed_count: installed = " (installed by %d user%s)" % (installed_count, "s" if installed_count > 1 else "") else: installed = "" table.addItem("Extension", renderItem, extension_path + "/" + installed, buttons)
def renderManageExtensions(req, db, user): if not configuration.extensions.ENABLED: administrators = dbutils.getAdministratorContacts(db, as_html=True) raise page.utils.DisplayMessage( title="Extension support not enabled", body=(("<p>This Critic system does not support extensions.</p>" "<p>Contact %s to have it enabled, or see the " "<a href='/tutorial?item=administration#extensions'>" "section on extensions</a> in the system administration " "tutorial for more information.</p>") % administrators), html=True) cursor = db.cursor() what = req.getParameter("what", "available") selected_versions = page.utils.json_decode(req.getParameter("select", "{}")) focused = req.getParameter("focus", None) if what == "installed": title = "Installed Extensions" listed_extensions = [] for extension_id, _, _, _ in Extension.getInstalls(db, user): try: listed_extensions.append(Extension.fromId(db, extension_id)) except ExtensionError as error: listed_extensions.append(error) else: title = "Available Extensions" listed_extensions = Extension.find(db) req.content_type = "text/html; charset=utf-8" document = htmlutils.Document(req) document.setTitle("Manage Extensions") html = document.html() head = html.head() body = html.body() def generateRight(target): target.a("button", href="tutorial?item=extensions").text("Tutorial") target.text(" ") target.a("button", href="tutorial?item=extensions-api").text("API Documentation") page.utils.generateHeader(body, db, user, current_page="extensions", generate_right=generateRight) document.addExternalStylesheet("resource/manageextensions.css") document.addExternalScript("resource/manageextensions.js") document.addInternalScript(user.getJS()) table = page.utils.PaleYellowTable(body, title) def addTitleRightLink(url, label): if user.name != req.user: url += "&user=%s" % user.name table.titleRight.text(" ") table.titleRight.a(href=url).text("[" + label + " extensions]") if what != "installed" or focused: addTitleRightLink("/manageextensions?what=installed", "installed") if what != "available" or focused: addTitleRightLink("/manageextensions?what=available", "available") for item in listed_extensions: if isinstance(item, ExtensionError): extension_error = item extension = item.extension else: extension_error = None extension = item if focused and extension.getKey() != focused: continue extension_path = extension.getPath() if extension.isSystemExtension(): hosting_user = None else: hosting_user = extension.getAuthor(db) selected_version = selected_versions.get(extension.getKey(), False) installed_sha1, installed_version = extension.getInstalledVersion(db, user) universal_sha1, universal_version = extension.getInstalledVersion(db, None) installed_upgradeable = universal_upgradeable = False if extension_error is None: if installed_sha1: current_sha1 = extension.getCurrentSHA1(installed_version) installed_upgradeable = installed_sha1 != current_sha1 if universal_sha1: current_sha1 = extension.getCurrentSHA1(universal_version) universal_upgradeable = universal_sha1 != current_sha1 def massage_version(version): if version is None: return "live" elif version: return "version/%s" % version else: return None if selected_version is False: selected_version = installed_version if selected_version is False: selected_version = universal_version install_version = massage_version(selected_version) installed_version = massage_version(installed_version) universal_version = massage_version(universal_version) manifest = None if extension_error is None: try: if selected_version is False: manifest = extension.getManifest() else: manifest = extension.getManifest(selected_version) except ManifestError as error: pass elif installed_sha1: manifest = extension.getManifest(installed_version, installed_sha1) elif universal_sha1: manifest = extension.getManifest(universal_version, universal_sha1) if manifest: if what == "available" and manifest.hidden: # Hide from view unless the user is hosting the extension, or is # an administrator and the extension is a system extension. if extension.isSystemExtension(): if not user.hasRole(db, "administrator"): continue elif hosting_user != user: continue else: if hosting_user != user: continue extension_id = extension.getExtensionID(db, create=False) if not user.isAnonymous(): buttons = [] if extension_id is not None: cursor.execute("""SELECT 1 FROM extensionstorage WHERE extension=%s AND uid=%s""", (extension_id, user.id)) if cursor.fetchone(): buttons.append(("Clear storage", ("clearExtensionStorage(%s, %s)" % (htmlutils.jsify(extension.getAuthorName()), htmlutils.jsify(extension.getName()))))) if not installed_version: if manifest and install_version and install_version != universal_version: buttons.append(("Install", ("installExtension(%s, %s, %s)" % (htmlutils.jsify(extension.getAuthorName()), htmlutils.jsify(extension.getName()), htmlutils.jsify(install_version))))) else: buttons.append(("Uninstall", ("uninstallExtension(%s, %s)" % (htmlutils.jsify(extension.getAuthorName()), htmlutils.jsify(extension.getName()))))) if manifest and (install_version != installed_version or (installed_sha1 and installed_upgradeable)): if install_version == installed_version: label = "Upgrade" else: label = "Install" buttons.append(("Upgrade", ("reinstallExtension(%s, %s, %s)" % (htmlutils.jsify(extension.getAuthorName()), htmlutils.jsify(extension.getName()), htmlutils.jsify(install_version))))) if user.hasRole(db, "administrator"): if not universal_version: if manifest and install_version: buttons.append(("Install (universal)", ("installExtension(%s, %s, %s, true)" % (htmlutils.jsify(extension.getAuthorName()), htmlutils.jsify(extension.getName()), htmlutils.jsify(install_version))))) else: buttons.append(("Uninstall (universal)", ("uninstallExtension(%s, %s, true)" % (htmlutils.jsify(extension.getAuthorName()), htmlutils.jsify(extension.getName()))))) if manifest and (install_version != universal_version or (universal_sha1 and universal_upgradeable)): if install_version == universal_version: label = "Upgrade (universal)" else: label = "Install (universal)" buttons.append((label, ("reinstallExtension(%s, %s, %s, true)" % (htmlutils.jsify(extension.getAuthorName()), htmlutils.jsify(extension.getName()), htmlutils.jsify(universal_version))))) else: buttons = None def renderItem(target): target.span("name").innerHTML(extension.getTitle(db, html=True)) if hosting_user: is_author = manifest and manifest.isAuthor(db, hosting_user) is_sole_author = is_author and len(manifest.authors) == 1 else: is_sole_author = False if extension_error is None: span = target.span("details") span.b().text("Details: ") select = span.select("details", critic_author=extension.getAuthorName(), critic_extension=extension.getName()) select.option(value='', selected="selected" if selected_version is False else None).text("Select version") versions = extension.getVersions() if versions: optgroup = select.optgroup(label="Official Versions") for version in versions: optgroup.option(value="version/%s" % version, selected="selected" if selected_version == version else None).text("%s" % version.upper()) optgroup = select.optgroup(label="Development") optgroup.option(value='live', selected="selected" if selected_version is None else None).text("LIVE") if manifest: is_installed = bool(installed_version) if is_installed: target.span("installed").text(" [installed]") else: is_installed = bool(universal_version) if is_installed: target.span("installed").text(" [installed (universal)]") target.div("description").preformatted().text(manifest.description, linkify=True) if not is_sole_author: authors = target.div("authors") authors.b().text("Author%s:" % ("s" if len(manifest.authors) > 1 else "")) authors.text(", ".join(author.name for author in manifest.getAuthors())) else: is_installed = False div = target.div("description broken").preformatted() if extension_error is None: anchor = div.a(href="loadmanifest?key=%s" % extension.getKey()) anchor.text("[This extension has an invalid MANIFEST file]") else: div.text("[This extension has been deleted or has become inaccessible]") if selected_version is False: return pages = [] injects = [] processcommits = [] filterhooks = [] scheduled = [] if manifest: for role in manifest.roles: if isinstance(role, PageRole): pages.append(role) elif isinstance(role, InjectRole): injects.append(role) elif isinstance(role, ProcessCommitsRole): processcommits.append(role) elif isinstance(role, FilterHookRole): filterhooks.append(role) elif isinstance(role, ScheduledRole): scheduled.append(role) role_table = target.table("roles") if pages: role_table.tr().th(colspan=2).text("Pages") for role in pages: row = role_table.tr() url = "%s/%s" % (dbutils.getURLPrefix(db, user), role.pattern) if is_installed and "*" not in url: row.td("pattern").a(href=url).text(url) else: row.td("pattern").text(url) td = row.td("description") td.text(role.description) if injects: role_table.tr().th(colspan=2).text("Page Injections") for role in injects: row = role_table.tr() row.td("pattern").text("%s/%s" % (dbutils.getURLPrefix(db, user), role.pattern)) td = row.td("description") td.text(role.description) if processcommits: role_table.tr().th(colspan=2).text("ProcessCommits hooks") ul = role_table.tr().td(colspan=2).ul() for role in processcommits: li = ul.li() li.text(role.description) if filterhooks: role_table.tr().th(colspan=2).text("FilterHook hooks") for role in filterhooks: row = role_table.tr() row.td("title").text(role.title) row.td("description").text(role.description) if scheduled: role_table.tr().th(colspan=2).text("Scheduled hooks") for role in scheduled: row = role_table.tr() row.td("pattern").text("%s @ %s" % (role.frequency, role.at)) td = row.td("description") td.text(role.description) installed_by = "" if extension_id is not None: cursor.execute("""SELECT uid FROM extensioninstalls JOIN extensions ON (extensions.id=extensioninstalls.extension) WHERE extensions.id=%s""", (extension.getExtensionID(db, create=False),)) user_ids = set(user_id for user_id, in cursor.fetchall()) if user_ids: installed_by = " (installed" if None in user_ids: installed_by += " universally" user_ids.remove(None) if user_ids: installed_by += " and" if user_ids: installed_by += (" by %d user%s" % (len(user_ids), "s" if len(user_ids) > 1 else "")) installed_by += ")" table.addItem("Extension", renderItem, extension_path + "/" + installed_by, buttons) document.addInternalScript("var selected_versions = %s;" % page.utils.json_encode(selected_versions)) return document