Author: matevz
Date: Sat Mar 30 16:22:41 2013
New Revision: 1462792
URL: http://svn.apache.org/r1462792
Log:
Ref. #470, #430 - implemented admin pages for linking repositories to products
Added:
bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/templates/repository_links.html
Modified:
bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/product_admin.py
bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/versioncontrol.py
Modified:
bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/product_admin.py
URL:
http://svn.apache.org/viewvc/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/product_admin.py?rev=1462792&r1=1462791&r2=1462792&view=diff
==============================================================================
---
bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/product_admin.py
(original)
+++
bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/product_admin.py
Sat Mar 30 16:22:41 2013
@@ -36,6 +36,11 @@ from multiproduct.env import ProductEnvi
from multiproduct.model import Product
from multiproduct.perm import sudo
+import multiproduct.versioncontrol
+import trac.versioncontrol.admin
+from trac.versioncontrol import DbRepositoryProvider, RepositoryManager
+from multiproduct.util import ReplacementComponent
+
#--------------------------
# Product admin panel
#--------------------------
@@ -364,3 +369,63 @@ class DefaultProductAdminWhitelist(Compo
#yield 'accounts', 'users'
yield 'ticket', '*'
yield 'versioncontrol', 'repository'
+
+
+class ProductRepositoryAdminPanel(ReplacementComponent,
trac.versioncontrol.admin.RepositoryAdminPanel):
+ """Web admin panel for repository administration, product-aware."""
+
+ implements(trac.admin.IAdminPanelProvider)
+
+ # IAdminPanelProvider methods
+
+ def get_admin_panels(self, req):
+ if 'VERSIONCONTROL_ADMIN' in req.perm:
+ yield ('versioncontrol', _('Version Control'), 'repository',
+ _('Repository Links') if isinstance(self.env,
ProductEnvironment)
+ else _('Repositories'))
+
+ def render_admin_panel(self, req, category, page, path_info):
+ if not isinstance(self.env, ProductEnvironment):
+ return super(ProductRepositoryAdminPanel, self).render_admin_panel(
+ req, category, page, path_info)
+
+ req.perm.require('VERSIONCONTROL_ADMIN')
+ db_provider = self.env[DbRepositoryProvider]
+
+ if req.method == 'POST' and db_provider:
+ if req.args.get('remove'):
+ repolist = req.args.get('sel')
+ if repolist:
+ if isinstance(repolist, basestring):
+ repolist = [repolist, ]
+ for reponame in repolist:
+ db_provider.unlink_product(reponame)
+ elif req.args.get('addlink') is not None and db_provider:
+ reponame = req.args.get('repository')
+ db_provider.link_product(reponame)
+ req.redirect(req.href.admin(category, page))
+
+ # Retrieve info for all product repositories
+ rm_product = RepositoryManager(self.env)
+ rm_product.reload_repositories()
+ all_product_repos = rm_product.get_all_repositories()
+ repositories = dict((reponame, self._extend_info(
+ reponame, info.copy(), True))
+ for (reponame, info) in
+ all_product_repos.iteritems())
+ types = sorted([''] + rm_product.get_supported_types())
+
+ # construct a list of all repositores not linked to this product
+ rm = RepositoryManager(self.env.parent)
+ all_repos = rm.get_all_repositories()
+ unlinked_repositories = { k: all_repos[k] for k in sorted(
+ set(all_repos) - set(all_product_repos)) }
+
+ data = {'types': types, 'default_type': rm_product.repository_type,
+ 'repositories': repositories,
+ 'unlinked_repositories': unlinked_repositories}
+ return 'repository_links.html', data
+
+trac.versioncontrol.admin.RepositoryAdminPanel = ProductRepositoryAdminPanel
+
+
Added:
bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/templates/repository_links.html
URL:
http://svn.apache.org/viewvc/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/templates/repository_links.html?rev=1462792&view=auto
==============================================================================
---
bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/templates/repository_links.html
(added)
+++
bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/templates/repository_links.html
Sat Mar 30 16:22:41 2013
@@ -0,0 +1,93 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:i18n="http://genshi.edgewall.org/i18n">
+ <xi:include href="admin.html" />
+ <head>
+ <title>Repository Links</title>
+ </head>
+ <body>
+ <h2>Manage repository links</h2>
+ <div class="row">
+ <div class="span8">
+ <form id="trac-repository_table" method="post" action=""
+ py:with="sorted_repos = sorted(repositories.iteritems(), key=lambda
item: item[0].lower())">
+ <table py:if="sorted_repos" id="trac-reposlist"
+ class="table table-striped table-condensed table-bordered">
+ <thead>
+ <tr>
+ <th class="sel"><i class="icon-check"></i></th>
+ <th>Name</th>
+ <th>Type</th>
+ <th>Directory</th>
+ <th>Revision</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr py:for="(reponame, info) in sorted_repos">
+ <td class="sel"><input py:if="info.editable" type="checkbox"
name="sel" value="$info.name"/></td>
+ <td class="name">
+ <a href="${panel_href(info.name or
'(default)')}">${info.name or _('(default)')}</a>
+ </td>
+ <td>${(info.type or _('(default)')) if not info.alias else
None}</td>
+ <td py:choose="">
+ <py:when test="info.dir">$info.prettydir</py:when>
+ <em py:otherwise="" i18n:msg="repo">Alias of ${info.alias or
_('(default)')}</em>
+ </td>
+ <td><a py:if="info.rev" href="${href.changeset(info.rev,
reponame) or None}">[$info.display_rev]</a></td>
+ </tr>
+ </tbody>
+ </table>
+
+ <div py:if="not sorted_repos" class="alert alert-info">No linked
repositories.</div>
+
+ <div class="buttons">
+ <input class="btn" type="submit" name="refresh"
value="${_('Refresh')}"/>
+ <input py:if="sorted_repos" class="btn" type="submit"
+ name="remove" value="${_('Remove selected items')}"/>
+ </div>
+ </form>
+ </div>
+
+ <div class="span8">
+ <h4>Add repository link</h4>
+ <py:choose test="">
+ <py:when test="unlinked_repositories">
+ <form class="form-inline" id="repository-link" method="post"
action="">
+ <select name="repository">
+ <option py:for="r,v in unlinked_repositories.iteritems()"
value="$r">$v.name</option>
+ </select>
+ <button type="submit" name="addlink" class="btn">Add</button>
+ </form>
+ </py:when>
+ <py:otherwise>
+ <div class="alert alert-info">No repositories to add.</div>
+ </py:otherwise>
+ </py:choose>
+ </div>
+ </div>
+ </body>
+</html>
+
Modified:
bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/versioncontrol.py
URL:
http://svn.apache.org/viewvc/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/versioncontrol.py?rev=1462792&r1=1462791&r2=1462792&view=diff
==============================================================================
---
bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/versioncontrol.py
(original)
+++
bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/versioncontrol.py
Sat Mar 30 16:22:41 2013
@@ -22,10 +22,12 @@ import os.path
from trac.util.concurrency import threading
from trac.core import implements
import trac.versioncontrol.api
+from trac.versioncontrol import RepositoryManager
import trac.admin
import trac.web.api
import trac.resource
from multiproduct.util import ReplacementComponent
+from multiproduct.env import ProductEnvironment
class DbRepositoryProvider(ReplacementComponent,
trac.versioncontrol.api.DbRepositoryProvider):
"""Inplace replacement for trac.versioncontrol.api.DbRepositoryProvider.
Filters
@@ -52,7 +54,7 @@ class DbRepositoryProvider(ReplacementCo
repos.setdefault(id, {})[name] = value
reponames = {}
for id, info in repos.iteritems():
- if 'product' in info and \
+ if not 'product' in info or \
not self.env.product.prefix in info['product'].split(','):
# skip repository if not soft linked from the current
# product environment
@@ -66,6 +68,25 @@ class DbRepositoryProvider(ReplacementCo
else:
return super(DbRepositoryProvider, self).get_repositories()
+ def link_product(self, reponame):
+ if not isinstance(self.env, ProductEnvironment):
+ return
+ rm = RepositoryManager(self.env.parent)
+ repoid = rm.get_repository_id(reponame)
+ with self.env.db_direct_transaction as db:
+ db("""INSERT INTO repository (id, name, value)
+ VALUES(%s, 'product', '%s')""" %
+ (repoid, self.env.product.prefix))
+
+ def unlink_product(self, reponame):
+ if not isinstance(self.env, ProductEnvironment):
+ return
+ rm = RepositoryManager(self.env.parent)
+ repoid = rm.get_repository_id(reponame)
+ with self.env.db_direct_transaction as db:
+ db("""DELETE FROM repository WHERE id=%s AND name='product'
+ AND value='%s'""" % (repoid, self.env.product.prefix))
+
trac.versioncontrol.api.DbRepositoryProvider = DbRepositoryProvider
trac.versioncontrol.DbRepositoryProvider = DbRepositoryProvider