class EnvironmentTestCase(unittest.TestCase): def setUp(self): env_path = os.path.join(tempfile.gettempdir(), 'trac-tempenv') self.env = Environment(env_path, create=True) self.db = self.env.get_db_cnx() def tearDown(self): self.db.close() self.env.shutdown() # really closes the db connections shutil.rmtree(self.env.path) def test_get_version(self): """Testing env.get_version""" assert self.env.get_version() == db_default.db_version def test_get_known_users(self): """Testing env.get_known_users""" cursor = self.db.cursor() cursor.executemany("INSERT INTO session VALUES (%s,%s,0)", [('123', 0),('tom', 1), ('joe', 1), ('jane', 1)]) cursor.executemany("INSERT INTO session_attribute VALUES (%s,%s,%s,%s)", [('123', 0, 'email', '*****@*****.**'), ('tom', 1, 'name', 'Tom'), ('tom', 1, 'email', '*****@*****.**'), ('joe', 1, 'email', '*****@*****.**'), ('jane', 1, 'name', 'Jane')]) users = {} for username,name,email in self.env.get_known_users(self.db): users[username] = (name, email) assert not users.has_key('anonymous') self.assertEqual(('Tom', '*****@*****.**'), users['tom']) self.assertEqual((None, '*****@*****.**'), users['joe']) self.assertEqual(('Jane', None), users['jane'])
class EnvironmentTestCase(unittest.TestCase): def setUp(self): env_path = os.path.join(tempfile.gettempdir(), 'trac-tempenv') self.env = Environment(env_path, create=True, db_str='sqlite:db/trac.db') self.db = self.env.get_db_cnx() def tearDown(self): self.db.close() self.env.shutdown() # really closes the db connections shutil.rmtree(self.env.path) def test_get_version(self): """Testing env.get_version""" assert self.env.get_version() == db_default.db_version def test_get_known_users(self): """Testing env.get_known_users""" cursor = self.db.cursor() cursor.execute("INSERT INTO session " "VALUES ('123',0,'email','*****@*****.**')") cursor.executemany("INSERT INTO session VALUES (%s,1,%s,%s)", [('tom', 'name', 'Tom'), ('tom', 'email', '*****@*****.**'), ('joe', 'email', '*****@*****.**'), ('jane', 'name', 'Jane')]) users = {} for username, name, email in self.env.get_known_users(self.db): users[username] = (name, email) assert not users.has_key('anonymous') self.assertEqual(('Tom', '*****@*****.**'), users['tom']) self.assertEqual((None, '*****@*****.**'), users['joe']) self.assertEqual(('Jane', None), users['jane'])
def rename_user(envpath, oldname, newname): """Deletes all watchlist DB entries => Uninstaller""" from trac.env import Environment try: env = Environment(envpath) except: print "Given path '%s' seems not to be a Trac environment." % envpath sys.exit(3) db = env.get_db_cnx() cursor = db.cursor() try: cursor.execute(""" UPDATE watchlist SET wluser=%s WHERE wluser=%s """, (newname,oldname)) cursor.execute(""" UPDATE watchlist_settings SET wluser=%s WHERE wluser=%s """, (newname,oldname)) print "Renamed user '%s' to '%s'." % (oldname,newname) db.commit() except Exception as e: db.rollback() print "Could not rename user: "******"Does the new user already exists?" sys.exit(3) db.commit() print "Finished."
def rename_user(envpath, oldname, newname): """Deletes all watchlist DB entries => Uninstaller""" from trac.env import Environment try: env = Environment(envpath) except: print "Given path '%s' seems not to be a Trac environment." % envpath sys.exit(3) db = env.get_db_cnx() cursor = db.cursor() try: cursor.execute( """ UPDATE watchlist SET wluser=%s WHERE wluser=%s """, (newname, oldname)) cursor.execute( """ UPDATE watchlist_settings SET wluser=%s WHERE wluser=%s """, (newname, oldname)) print "Renamed user '%s' to '%s'." % (oldname, newname) db.commit() except Exception as e: db.rollback() print "Could not rename user: "******"Does the new user already exists?" sys.exit(3) db.commit() print "Finished."
def fetchRecipes(trac_env): env = Environment(trac_env) db = env.get_db_cnx() cursor = db.cursor() cursor.execute("SELECT path,active,recipe,min_rev,max_rev,label,description,name FROM bitten_config") for row in cursor: (path, active, recipe, min_rev, max_rev, label, description, name) = row writeFile(trac_env, name, (path, active, recipe, min_rev, max_rev, label, description))
def Main(opts): """ Cross your fingers and pray """ env = Environment(opts.envpath) from tractags.api import TagSystem tlist = opts.tags or split_tags(env.config.get('blog', 'default_tag', 'blog')) tags = TagSystem(env) req = Mock(perm=MockPerm()) blog = tags.query(req, ' '.join(tlist + ['realm:wiki'])) cnx = env.get_db_cnx() for resource, page_tags in list(blog): try: page = WikiPage(env, version=1, name=resource.id) _, publish_time, author, _, _ = page.get_history().next() if opts.deleteonly: page.delete() continue categories = ' '.join([t for t in page_tags if t not in tlist]) page = WikiPage(env, name=resource.id) for version, version_time, version_author, version_comment, \ _ in page.get_history(): # Currently the basename of the post url is used due to # http://trac-hacks.org/ticket/2956 #name = resource.id.replace('/', '_') name = resource.id # extract title from text: fulltext = page.text match = _title_split_match(fulltext) if match: title = match.group(1) fulltext = match.group(2) else: title = name body = fulltext print "Adding post %s, v%s: %s" % (name, version, title) insert_blog_post(cnx, name, version, title, body, publish_time, version_time, version_comment, version_author, author, categories) reparent_blog_attachments(env, resource.id, name) continue cnx.commit() if opts.delete: page.delete() continue except: env.log.debug("Error loading wiki page %s" % resource.id, exc_info=True) print "Failed to add post %s, v%s: %s" % (name, version, title) cnx.rollback() cnx.close() return 1 cnx.close() return 0
def get_trac_user(path, username): from trac.env import Environment env = Environment(path) db = env.get_db_cnx() cursor = db.cursor() cursor.execute( "SELECT name, value" " FROM session_attribute" " WHERE sid='%s'" " AND (name='email' OR name='name')" % username ) return dict((name, value) for name, value in cursor)
def Main(opts): """ Cross your fingers and pray """ env = Environment(opts.envpath) from tractags.api import TagSystem tlist = opts.tags or split_tags( env.config.get('blog', 'default_tag', 'blog')) tags = TagSystem(env) req = Mock(perm=MockPerm()) blog = tags.query(req, ' '.join(tlist + ['realm:wiki'])) cnx = env.get_db_cnx() for resource, page_tags in list(blog): try: page = WikiPage(env, version=1, name=resource.id) _, publish_time, author, _, _ = page.get_history().next() if opts.deleteonly: page.delete() continue categories = ' '.join([t for t in page_tags if t not in tlist]) page = WikiPage(env, name=resource.id) for version, version_time, version_author, version_comment, \ _ in page.get_history(): # Currently the basename of the post url is used due to # http://trac-hacks.org/ticket/2956 #name = resource.id.replace('/', '_') name = resource.id # extract title from text: fulltext = page.text match = _title_split_match(fulltext) if match: title = match.group(1) fulltext = match.group(2) else: title = name body = fulltext print "Adding post %s, v%s: %s" % (name, version, title) insert_blog_post(cnx, name, version, title, body, publish_time, version_time, version_comment, version_author, author, categories) reparent_blog_attachments(env, resource.id, name) continue cnx.commit() if opts.delete: page.delete() continue except: env.log.debug("Error loading wiki page %s" % resource.id, exc_info=True) print "Failed to add post %s, v%s: %s" % (name, version, title) cnx.rollback() cnx.close() return 1 cnx.close() return 0
class TicketTemplateTestCase(unittest.TestCase): def setUp(self): # self.env = EnvironmentStub() env_path = os.path.join(tempfile.gettempdir(), 'trac-tempenv') self.env = Environment(env_path, create=True) self.db = self.env.get_db_cnx() self.compmgr = ComponentManager() # init TicketTemplateModule self.tt = ttadmin.TicketTemplateModule(self.compmgr) setattr(self.tt, "env", self.env) def tearDown(self): self.db.close() self.env.shutdown() # really closes the db connections shutil.rmtree(self.env.path) def test_get_active_navigation_item(self): req = Mock(path_info='/tickettemplate') self.assertEqual('tickettemplate', self.tt.get_active_navigation_item(req)) req = Mock(path_info='/something') self.assertNotEqual('tickettemplate', self.tt.match_request(req)) def test_get_navigation_items(self): req = Mock(href=Mock( tickettemplate=lambda: "/trac-tempenv/tickettemplate")) a, b, c = self.tt.get_navigation_items(req).next() self.assertEqual('mainnav', a) self.assertEqual('tickettemplate', b) def test_match_request(self): req = Mock(path_info='/tickettemplate') self.assertEqual(True, self.tt.match_request(req)) req = Mock(path_info='/something') self.assertEqual(False, self.tt.match_request(req)) def test_getTicketTypeNames(self): options = self.tt._getTicketTypeNames() self.assertEqual(["default", "defect", "enhancement", "task"], options) def test_loadSaveTemplateText(self): for tt_name, tt_text in [ ("default", "default text"), ("defect", "defect text"), ("enhancement", "enhancement text"), ("task", "task text"), ]: self.tt._saveTemplateText(tt_name, tt_text) self.assertEqual(tt_name + " text", self.tt._loadTemplateText(tt_name))
class TracDatabase(object): def __init__(self, path): self.env = Environment(path) self._db = self.env.get_db_cnx() def db(self): return self._db def hasTickets(self): c = self.db().cursor() c.execute("SELECT count(*) FROM Ticket") return int(c.fetchall()[0][0]) > 0 def setList(self, name, values): c = self.db().cursor() c.execute("DELETE FROM %s" % name) for v in values: print " inserting %s '%s'" % (name, v) c.execute("INSERT INTO " + name + " (name) VALUES (%s)", (v,)) self.db().commit() def setEnumList(self, name, values): c = self.db().cursor() c.execute("DELETE FROM enum WHERE type=%s", (name,)) for n, v in enumerate(values): print " inserting %s '%s'" % (name, v) c.execute("INSERT INTO enum (type, name, value) VALUES (%s,%s,%s)", (name, v, n)) self.db().commit() def clean(self): print "\nCleaning all tickets..." c = self.db().cursor() c.execute("DELETE FROM ticket_change") c.execute("DELETE FROM ticket") c.execute("DELETE FROM attachment") c.execute("DELETE FROM ticket_custom") self.db().commit() attachments_dir = os.path.join(os.path.normpath(self.env.path), "attachments") remove_recursively(attachments_dir) if not os.path.isdir(attachments_dir): os.mkdir(attachments_dir) def addAttachment(self, ticket_id, filename, datafile, filesize, author, description, upload_time): # copied from bugzilla2trac attachment = Attachment(self.env, 'ticket', ticket_id) attachment.author = author attachment.description = description attachment.insert(filename, datafile, filesize, upload_time) del attachment
def fetchRecipes(trac_env): env = Environment(trac_env) db = env.get_db_cnx() cursor = db.cursor() cursor.execute( "SELECT path,active,recipe,min_rev,max_rev,label,description,name FROM bitten_config" ) for row in cursor: (path, active, recipe, min_rev, max_rev, label, description, name) = row writeFile(trac_env, name, (path, active, recipe, min_rev, max_rev, label, description))
class TracDatabase(object): def __init__(self, path): self.env = Environment(path) self._db = self.env.get_db_cnx() def db(self): return self._db def hasTickets(self): c = self.db().cursor() c.execute("SELECT count(*) FROM Ticket") return int(c.fetchall()[0][0]) > 0 def setList(self, name, values): c = self.db().cursor() c.execute("DELETE FROM %s" % name) for v in values: print " inserting %s '%s'" % (name, v) c.execute("INSERT INTO " + name + " (name) VALUES (%s)", (v, )) self.db().commit() def setEnumList(self, name, values): c = self.db().cursor() c.execute("DELETE FROM enum WHERE type=%s", (name, )) for n, v in enumerate(values): print " inserting %s '%s'" % (name, v) c.execute("INSERT INTO enum (type, name, value) VALUES (%s,%s,%s)", (name, v, n)) self.db().commit() def clean(self): print "\nCleaning all tickets..." c = self.db().cursor() c.execute("DELETE FROM ticket_change") c.execute("DELETE FROM ticket") c.execute("DELETE FROM attachment") c.execute("DELETE FROM ticket_custom") self.db().commit() attachments_dir = os.path.join(os.path.normpath(self.env.path), "attachments") remove_recursively(attachments_dir) if not os.path.isdir(attachments_dir): os.mkdir(attachments_dir) def addAttachment(self, ticket_id, filename, datafile, filesize, author, description, upload_time): # copied from bugzilla2trac attachment = Attachment(self.env, 'ticket', ticket_id) attachment.author = author attachment.description = description attachment.insert(filename, datafile, filesize, upload_time) del attachment
def do_purge(self, req, path, users): """Purge obsolete data - i.e. environment data (sessions, preferences, permissions) from users no longer existing @param req @param path path to the trac env to purge @param users users to keep @return boolean success @return msg info """ self.env.log.debug('+ Purging obsolete data') dryrun = self.env.config.getbool('user_sync','dryrun',True) sql = [] envpath, tracenv = os.path.split(path) try: env = Environment(path) except IOError: self.env.log.debug('Could not initialize environment at %s' % (path,)) return False, 'Could not initialize environment at %s' % (path,) perm = PermissionSystem(env) if not 'TRAC_ADMIN' in perm.get_user_permissions(req.perm.username): raise PermissionError excludes = self.get_perm_groups(path)+users protect = "'"+"','".join(excludes)+"'" self.env.log.debug("Excluding from purge: %s" % (protect,)) db = env.get_db_cnx() cursor = db.cursor() if not dryrun: self.env.log.debug('Updating database for %s' % (tracenv,)) cursor.execute('DELETE FROM auth_cookie WHERE name NOT IN (%s)' % (protect,)) cursor.execute('DELETE FROM session WHERE sid NOT IN (%s)' % (protect,)) cursor.execute('DELETE FROM session_attribute WHERE sid NOT IN (%s)' % (protect,)) cursor.execute('DELETE FROM permission WHERE username NOT IN (%s)' % (protect,)) db.commit() sql_file_path = self.env.config.get('user_sync','sql_file_path') or os.path.join(self.env.path,'log') if sql_file_path.lower() == 'none': self.env.log.debug('SQLFile disabled (sql_file_path is "none")') else: sqlfile = '%s.sql' % (tracenv,) sqlfile = os.path.join(sql_file_path,sqlfile) self.env.log.debug('Writing SQL to %s' % (sqlfile,)) try: f = open(sqlfile,'a') f.write('\n--- SQL for purging Trac environment %s\n' % (tracenv,)); f.write('DELETE FROM auth_cookie WHERE name NOT IN (%s);\n' % (protect,)) f.write('DELETE FROM session WHERE sid NOT IN (%s);\n' % (protect,)) f.write('DELETE FROM session_attribute WHERE sid NOT IN (%s);\n' % (protect,)) f.write('DELETE FROM permission WHERE username NOT IN (%s);\n' % (protect,)) except IOError: self.env.log.debug('Could not write SQL file %s!' % (sqlfile,)) return False, 'Could not write SQL file %s!' % (sqlfile,) return True, 'Successfully purged environment %s' % (tracenv,)
class TicketTemplateTestCase(unittest.TestCase): def setUp(self): # self.env = EnvironmentStub() env_path = os.path.join(tempfile.gettempdir(), 'trac-tempenv') self.env = Environment(env_path, create=True) self.db = self.env.get_db_cnx() self.compmgr = ComponentManager() # init TicketTemplateModule self.tt = ttadmin.TicketTemplateModule(self.compmgr) setattr(self.tt, "env", self.env) def tearDown(self): self.db.close() self.env.shutdown() # really closes the db connections shutil.rmtree(self.env.path) def test_get_active_navigation_item(self): req = Mock(path_info='/tickettemplate') self.assertEqual('tickettemplate', self.tt.get_active_navigation_item(req)) req = Mock(path_info='/something') self.assertNotEqual('tickettemplate', self.tt.match_request(req)) def test_get_navigation_items(self): req = Mock(href=Mock(tickettemplate=lambda:"/trac-tempenv/tickettemplate")) a, b, c= self.tt.get_navigation_items(req).next() self.assertEqual('mainnav', a) self.assertEqual('tickettemplate', b) def test_match_request(self): req = Mock(path_info='/tickettemplate') self.assertEqual(True, self.tt.match_request(req)) req = Mock(path_info='/something') self.assertEqual(False, self.tt.match_request(req)) def test_getTicketTypeNames(self): options = self.tt._getTicketTypeNames() self.assertEqual(["default", "defect", "enhancement", "task"], options) def test_loadSaveTemplateText(self): for tt_name, tt_text in [("default", "default text"), ("defect", "defect text"), ("enhancement", "enhancement text"), ("task", "task text"), ]: self.tt._saveTemplateText(tt_name, tt_text) self.assertEqual(tt_name + " text", self.tt._loadTemplateText(tt_name))
def _setup(self, configuration = None): configuration = configuration or '[ticket-custom]\nmycustomfield = text\nmycustomfield.label = My Custom Field\nmycustomfield.order = 1' instancedir = os.path.join(tempfile.gettempdir(), 'test-importer._preview') if os.path.exists(instancedir): shutil.rmtree(instancedir, False) env = Environment(instancedir, create=True) open(os.path.join(os.path.join(instancedir, 'conf'), 'trac.ini'), 'a').write('\n' + configuration + '\n') db = env.get_db_cnx() _exec(db.cursor(), "INSERT INTO permission VALUES ('anonymous', 'REPORT_ADMIN') ") _exec(db.cursor(), "INSERT INTO permission VALUES ('anonymous', 'IMPORT_EXECUTE') ") db.commit() ImporterTestCase.TICKET_TIME = 1190909220 return Environment(instancedir)
def get_number_of_tickets_per_cr(self, project): settings = get_current_registry().settings if not settings: return tracenvs = settings.get('penelope.trac.envs') for trac in project.tracs: env = Environment('%s/%s' % (tracenvs, trac.trac_name)) db = env.get_db_cnx() cursor = db.cursor() cursor.execute("""SELECT c.value as cr, count(t.id) AS number FROM ticket t INNER JOIN ticket_custom c ON (t.id = c.ticket AND c.name = 'customerrequest') group by cr;""") tickets = cursor.fetchall() db.rollback() return dict(tickets)
def get_perm_groups(self,path): """Get array of permission groups (e.g. anonymous,authenticated) defined in the given environment. These 'users' should e.g. never be purged on cleanup """ users = [] env = Environment(path) sids = [] self.env.log.debug('Get users to keep from environment path %s' % (path,)) db = env.get_db_cnx() cursor = db.cursor() cursor.execute('SELECT DISTINCT username FROM permission WHERE username NOT IN (SELECT DISTINCT sid FROM session_attribute UNION SELECT DISTINCT sid FROM session UNION SELECT DISTINCT name FROM auth_cookie)') for row in cursor: users.append(row[0]) self.env.log.debug('Permission groups for %s: %s' % (path,','.join(users))) for user in env.config.getlist('user_sync','users_keep'): if not user in users: users.append(user) return users
def getMySQLEnvironment(opts): dburi = opts.mysql_uri env = Environment(opts.tracenv) env.config.set('trac', 'database', dburi) try: cnx = env.get_db_cnx() cur = cnx.cursor() cur.execute("select value from system where name = 'database_version'"); except ProgrammingError: cnx.rollback() DatabaseManager(env).init_db() DatabaseManager(env).shutdown() # if env.needs_upgrade(): # env.upgrade() return env
def get_tracenv_users(self, path, userlist=''): """Get array of users defined in the specified environment having data assigned @param path path to the environment @param userlist comma separated list of users to restrict the result to (e.g. the users from the password file), each user enclosed in single quotes (for SQL) @return array [0..n] of string users """ env = Environment(path) sids = [] self.env.log.debug('Get users from %s' % (path,)) db = env.get_db_cnx() cursor = db.cursor() if userlist: cursor.execute("SELECT DISTINCT sid FROM session_attribute WHERE sid IN (%s) AND name != 'enabled'" % (userlist,)) else: cursor.execute("SELECT DISTINCT sid FROM session_attribute WHERE name != 'enabled'") for row in cursor: sids.append(row[0]) return sids
def get_tracenv_userdata(self, req, path, userlist=''): """Retrieve account data from the environment at the specified path @param path path to the environment @param userlist comma separated list of users to restrict the result to (e.g. the users from the password file), each user enclosed in single quotes (for SQL) @return array (empty array if the environment uses a different password file than the master env calling us) """ self.env.log.debug('Get user data from %s' % (path,)) data = {} env = Environment(path) # if this environment uses a different password file, we return an empty dataset if self.env.config.get('account-manager','password_file') != env.config.get('account-manager','password_file'): self.env.log.info('Password files do not match, skipping environment %s' % (path,)) return data perm = PermissionSystem(env) if not 'TRAC_ADMIN' in perm.get_user_permissions(req.perm.username): raise PermissionError db = env.get_db_cnx() cursor = db.cursor() sync_fields = self.env.config.getlist('user_sync','sync_fields') attr = "'"+"','".join(sync_fields)+"','email_verification_sent_to','email_verification_token'" self.env.log.debug('* Checking attributes: %s' % (attr,)) if userlist: cursor.execute("SELECT sid,name,value FROM session_attribute WHERE sid IN (%s) AND name IN (%s)" % (userlist,attr,)) else: cursor.execute("SELECT sid,name,value FROM session_attribute WHERE name IN (%s)" % (attr,)) for row in cursor: if not row[0] in data: data[row[0]] = {} data[row[0]][row[1]] = row[2] for sid in data.iterkeys(): no_data = True for att in sync_fields: if att in data[sid]: no_data = False break if no_data: self.env.log.debug('No data for %s in %s' % (sid,path,)) data[sid] = Null continue data[sid]['path'] = path cursor.execute("SELECT authenticated FROM session_attribute WHERE sid='%s'" % (sid,)) for row in cursor: data[sid]['authenticated'] = row[0] cursor.execute("SELECT datetime(last_visit,'unixepoch') AS last_visit FROM session WHERE sid='%s'" % (sid,)) for row in cursor: data[sid]['last_visit'] = row[0] return data
def get_perm_groups(self, path): """Get array of permission groups (e.g. anonymous,authenticated) defined in the given environment. These 'users' should e.g. never be purged on cleanup """ users = [] env = Environment(path) sids = [] self.env.log.debug('Get users to keep from environment path %s' % (path, )) db = env.get_db_cnx() cursor = db.cursor() cursor.execute( 'SELECT DISTINCT username FROM permission WHERE username NOT IN (SELECT DISTINCT sid FROM session_attribute UNION SELECT DISTINCT sid FROM session UNION SELECT DISTINCT name FROM auth_cookie)' ) for row in cursor: users.append(row[0]) self.env.log.debug('Permission groups for %s: %s' % (path, ','.join(users))) for user in env.config.getlist('user_sync', 'users_keep'): if not user in users: users.append(user) return users
def getPostgreSQLEnvironment(opts): """ Create an Environment connected to the PostgreSQL database """ dburi = opts.pg_uri env = Environment(opts.tracenv) env.config.set('trac', 'database', dburi) try: cnx = env.get_db_cnx() cur = cnx.cursor() cur.execute("select value from system where name = 'database_version'"); except ProgrammingError: cnx.rollback() DatabaseManager(env).init_db() DatabaseManager(env).shutdown() for x in filter(None, [env.compmgr[cls] for cls in ComponentMeta._registry.get( IEnvironmentSetupParticipant, [])]): if isinstance(x, EnvironmentSetup): x.environment_created() if env.needs_upgrade(): env.upgrade() return env
def _setup(self, configuration=None): configuration = configuration or '[ticket-custom]\nmycustomfield = text\nmycustomfield.label = My Custom Field\nmycustomfield.order = 1' instancedir = os.path.join(tempfile.gettempdir(), 'test-importer._preview') if os.path.exists(instancedir): shutil.rmtree(instancedir, False) env = Environment(instancedir, create=True) open(os.path.join(os.path.join(instancedir, 'conf'), 'trac.ini'), 'a').write('\n' + configuration + '\n') db = env.get_db_cnx() _exec( db.cursor(), "INSERT INTO permission VALUES ('anonymous', 'REPORT_ADMIN') " ) _exec( db.cursor(), "INSERT INTO permission VALUES ('anonymous', 'IMPORT_EXECUTE') " ) db.commit() ImporterTestCase.TICKET_TIME = 1190909220 return Environment(instancedir)
def _create_a_project(self,owner,proj_name,proj_full_name,description,req): if "PROJECT_CREATE" in req.perm: inherit_file=self.env.config.get('projectsmanager','inherit_file') options=[ ('project','name',proj_full_name), ('project','descr',description), ('inherit','file',inherit_file) ] (projects_root_dir,_)=os.path.split(self.env.path) path = os.path.join(projects_root_dir,proj_name) self.log.debug('starting to create the environment.') Environment(path,True,options) env=Environment(path)# cmd: trac-admin path permission add XX TRAC_ADMIN cnx=env.get_db_cnx() cur=cnx.cursor() cur.execute("insert into permission values ('%s','TRAC_ADMIN');"%\ owner) cur.close() cnx.commit() cnx.close() else: pass
def get_tracenv_users(self, path, userlist=''): """Get array of users defined in the specified environment having data assigned @param path path to the environment @param userlist comma separated list of users to restrict the result to (e.g. the users from the password file), each user enclosed in single quotes (for SQL) @return array [0..n] of string users """ env = Environment(path) sids = [] self.env.log.debug('Get users from %s' % (path, )) db = env.get_db_cnx() cursor = db.cursor() if userlist: cursor.execute( "SELECT DISTINCT sid FROM session_attribute WHERE sid IN (%s) AND name != 'enabled'" % (userlist, )) else: cursor.execute( "SELECT DISTINCT sid FROM session_attribute WHERE name != 'enabled'" ) for row in cursor: sids.append(row[0]) return sids
def getPostgreSQLEnvironment(opts): """ Create an Environment connected to the PostgreSQL database """ dburi = opts.pg_uri env = Environment(opts.tracenv) env.config.set('trac', 'database', dburi) try: cnx = env.get_db_cnx() cur = cnx.cursor() cur.execute("select value from system where name = 'database_version'") except ProgrammingError: cnx.rollback() DatabaseManager(env).init_db() DatabaseManager(env).shutdown() for x in filter(None, [ env.compmgr[cls] for cls in ComponentMeta._registry.get( IEnvironmentSetupParticipant, []) ]): if isinstance(x, EnvironmentSetup): x.environment_created() if env.needs_upgrade(): env.upgrade() return env
class EnvironmentTestCase(unittest.TestCase): def setUp(self): env_path = os.path.join(tempfile.gettempdir(), "trac-tempenv") self.env = Environment(env_path, create=True) self.db = self.env.get_db_cnx() def tearDown(self): self.db.close() self.env.shutdown() # really closes the db connections shutil.rmtree(self.env.path) def test_get_version(self): """Testing env.get_version""" assert self.env.get_version() == db_default.db_version def test_get_known_users(self): """Testing env.get_known_users""" cursor = self.db.cursor() cursor.executemany("INSERT INTO session VALUES (%s,%s,0)", [("123", 0), ("tom", 1), ("joe", 1), ("jane", 1)]) cursor.executemany( "INSERT INTO session_attribute VALUES (%s,%s,%s,%s)", [ ("123", 0, "email", "*****@*****.**"), ("tom", 1, "name", "Tom"), ("tom", 1, "email", "*****@*****.**"), ("joe", 1, "email", "*****@*****.**"), ("jane", 1, "name", "Jane"), ], ) users = {} for username, name, email in self.env.get_known_users(self.db): users[username] = (name, email) assert not users.has_key("anonymous") self.assertEqual(("Tom", "*****@*****.**"), users["tom"]) self.assertEqual((None, "*****@*****.**"), users["joe"]) self.assertEqual(("Jane", None), users["jane"])
def _setup(self, configuration = None, plugin_dir=None): configuration = configuration or '[ticket-custom]\nmycustomfield = text\nmycustomfield.label = My Custom Field\nmycustomfield.order = 1\n' configuration += '\n[ticket]\ndefault_type = task\n' instancedir = os.path.join(tempfile.gettempdir(), 'test-importer._preview_%d' % self.index[0]) self.index[0] += 1 if os.path.exists(instancedir): shutil.rmtree(instancedir, False) env = Environment(instancedir, create=True) if plugin_dir: for file in os.listdir(plugin_dir): if file[0] == '.': continue shutil.copyfile(os.path.join(plugin_dir, file), os.path.join(instancedir, 'plugins', file)) open(os.path.join(os.path.join(instancedir, 'conf'), 'trac.ini'), 'a').write('\n' + configuration + '\n') db = env.get_db_cnx() _exec(db.cursor(), "INSERT INTO permission VALUES ('anonymous', 'REPORT_ADMIN') ") _exec(db.cursor(), "INSERT INTO permission VALUES ('anonymous', 'IMPORT_EXECUTE') ") db.commit() ImporterTestCase.TICKET_TIME = 1190909220 return Environment(instancedir)
def delete_watchlist_tables(envpath, tables=('watchlist','watchlist_settings','system'), user=None): """Deletes all watchlist DB entries => Uninstaller""" from trac.env import Environment try: env = Environment(envpath) except: print "Given path '%s' seems not to be a Trac environment." % envpath sys.exit(3) db = env.get_db_cnx() if user is not None: cursor = db.cursor() if 'watchlist' in tables: try: cursor.execute("DELETE FROM watchlist WHERE wluser=%s", (user,)) print "Deleted user entries from 'watchlist' table." except Exception as e: db.rollback() print "Could not delete user entry from 'watchlist' table: "\ + unicode(e) cursor = db.cursor() if 'watchlist_settings' in tables: try: cursor.execute("DELETE FROM watchlist_settings WHERE wluser=%s", (user,)) print "Deleted user entries from 'watchlist_settings' table." except Exception as e: db.rollback() print "Could not delete user entry from 'watchlist_settings' table: "\ + unicode(e) db.commit() print "Finished." return if 'watchlist' in tables: cursor = db.cursor() try: cursor.execute("DROP TABLE watchlist") print "Deleted 'watchlist' table." except: db.rollback() print "No 'watchlist' table for deletion found." if 'watchlist_settings' in tables: cursor = db.cursor() try: cursor.execute("DROP TABLE watchlist_settings") print "Deleted 'watchlist_settings' table." except: db.rollback() print "No 'watchlist_settings' table for deletion found." if 'system' in tables: cursor = db.cursor() try: cursor.execute("DELETE FROM system WHERE name='watchlist_version'") print "Deleted watchlist version entry from system table." except Exception as e: db.rollback() print "Could not delete 'watchlist_version' from 'system' table: "\ + unicode(e) db.commit() print "Finished."
def update_tracenv_userdata(self, req, path, userdata): """Update the userdata in the specified environment using the records passed by userdata. @param path : path to the trac environment to update @param userdata : collection of userdata as returned from merge() @return success : boolean @return msg : details """ sql = [] exists = '' msg = '' envpath, tracenv = os.path.split(path) self.env.log.debug('Updating userdata in environment %s' % (path,)) dryrun = self.env.config.getbool('user_sync','dryrun',True) if not dryrun: self.env.log.debug('HOT!!! We are NOT in dryrun mode!') else: self.env.log.debug('TESTING - we ARE in dryrun mode.') try: env = Environment(path) except IOError: self.env.log.debug('Could not initialize environment at %s' % (path,)) return False, 'Could not initialize environment at %s' % (path,) perm = PermissionSystem(env) if not 'TRAC_ADMIN' in perm.get_user_permissions(req.perm.username): raise PermissionError db = env.get_db_cnx() cursor = db.cursor() if not dryrun: self.env.log.debug('Updating database for %s' % (tracenv,)) for user in userdata: authenticated = userdata[user]['authenticated'] or 0 for att in userdata[user]: if att in ['path','authenticated','last_visit']: continue cursor.execute("SELECT value FROM session_attribute WHERE sid='%s' AND name='%s' AND authenticated=%s" % (user,att,authenticated,)) for row in cursor: exists = row[0] if exists: if exists == userdata[user][att]: continue if not dryrun: cursor.execute("UPDATE session_attribute SET value='%s' WHERE sid='%s' AND name='%s' AND authenticated=%s;\n" % (userdata[user][att],user,att,authenticated,)) sql.append("UPDATE session_attribute SET value='%s' WHERE sid='%s' AND name='%s' AND authenticated=%s;\n" % (userdata[user][att],user,att,authenticated,)) else: if not dryrun: cursor.execute("INSERT INTO session_attribute (sid,authenticated,name,value) VALUES('%s',%s,'%s','%s');\n" % (user,authenticated,att,userdata[user][att])) sql.append("INSERT INTO session_attribute (sid,authenticated,name,att) VALUES('%s',%s,'%s','%s');\n" % (user,authenticated,att,userdata[user][att])) if len(sql): if not dryrun: db.commit() sql_file_path = self.env.config.get('user_sync','sql_file_path') or os.path.join(self.env.path,'log') if sql_file_path.lower() == 'none': self.env.log.debug('SQLFile disabled (sql_file_path is "none")') else: sqlfile = '%s.sql' % (tracenv,) sqlfile = os.path.join(sql_file_path,sqlfile) try: if os.path.exists(sqlfile): os.unlink(sqlfile) self.env.log.debug('Writing SQL to %s' % (sqlfile,)) f = open(sqlfile,'a') f.write('--- SQL for Trac environment %s\n' % (tracenv,)); f.writelines(sql) f.close() except IOError: self.env.log.debug('Could not write SQL file %s!' % (sqlfile,)) return False, 'Could not write SQL file %s!' % (sqlfile,) except ValueError: self.env.log.debug('No value for sqlfile?') if dryrun: msg = 'Wrote SQL for Trac environment %s to %s' % (tracenv,sqlfile,) else: msg = 'Updated userdata in environment %s. SQL was additionally written to %s' % (tracenv,sqlfile,) else: msg = 'No updates for Trac environment %s' % (tracenv) self.env.log.debug('Done updating userdata in environment %s' % (path,)) return True, msg
import os, sys if os.environ['TRAC_VERSION'] in ('trunk', 'renderfilter'): import pkg_resources pkg_resources.require('Trac >= 0.11dev') from trac.core import * from trac.env import Environment from trac.wiki.model import WikiPage from trac.ticket.model import Ticket from trac.web.href import Href from genshi.core import * from genshi.builder import tag env = Environment(os.environ['TRAC']) db = env.get_db_cnx() cursor = db.cursor() class FakeReq(object): def __init__(self): self.href = Href(os.environ['TRAC_VERSION'] + '/' + os.environ['TRAC']) self.authname = 'anonymous' req = FakeReq() from tracforge.admin.query import MultiQuery, TracForgeQueryModule from trac.ticket.query import QueryModule q = MultiQuery(env, 'id!=0') d = q.execute(req)
class Trac(object): def __init__(self, path): '''Basic object that supports the wiki and all that jazz''' self._env = Environment(os.path.abspath(path)) purl = self._env.project_url if purl.endswith('/'): purl = purl[:-1] if purl: self.name = purl.split('/')[-1] else: self.name = self._env.project_name def listWikiPages(self): '''Return a list of all wiki pages that were not written by the 'trac' user''' db = self._env.get_db_cnx() cursor = db.cursor() wikiPagesQuery = "select distinct name from wiki where author != 'trac'" res = cursor.execute(wikiPagesQuery) pages = res.fetchall() names = [x[0] for x in pages] return names def listTickets(self): '''Return a list of all ticket numbers''' db = self._env.get_db_cnx() cursor = db.cursor() ticketsQuery = 'select distinct id from ticket' res = cursor.execute(ticketsQuery) ticketsRes = res.fetchall() tickets = [x[0] for x in ticketsRes] return tickets def maxTicket(self): '''Return the largest ticket number''' db = self._env.get_db_cnx() cursor = db.cursor() maxTicketQuery = 'select max(id) from ticket' res = cursor.execute(maxTicketQuery) (maxTicket, ) = res.fetchone() return maxTicket def listVersions(self): '''List all the versions''' db = self._env.get_db_cnx() cursor = db.cursor() versionsQuery = "select name from version" res = cursor.execute(versionsQuery) versions = [x[0] for x in res.fetchall()] return versions def listComponents(self): '''List all the ticket components''' db = self._env.get_db_cnx() cursor = db.cursor() componentsQuery = "select name from component" res = cursor.execute(componentsQuery) components = [x[0] for x in res.fetchall()] return components def listEnums(self): '''List all the enums''' db = self._env.get_db_cnx() cursor = db.cursor() enumsQuery = "select name, type from enum" res = cursor.execute(enumsQuery) return res.fetchall() def listMilestones(self): '''List all the milestones''' db = self._env.get_db_cnx() cursor = db.cursor() milestonesQuery = "select name from milestone" res = cursor.execute(milestonesQuery) milestones = [x[0] for x in res.fetchall()] return milestones def getAllInfo(self): all = {} all['wikiNames'] = self.listWikiPages() all['maxTicket'] = self.maxTicket() all['versions'] = self.listVersions() all['components'] = self.listComponents() all['enums'] = self.listEnums() all['milestones'] = self.listMilestones() return all def getWikiPageAll(self, page): '''Get all the versions of a wiki page as a list of dicts and a list of attachments''' db = self._env.get_db_cnx() cursor = db.cursor() pageCountRes = cursor.execute( 'select count(*) as count from wiki where name = %s', (page, )) pageCount = pageCountRes.fetchone()[0] assert pageCount >= 1, 'Page %s not found in %s' % (page, self.name) attachments = [] pageAttachmentQuery = "select type, id, filename, size, time, description, author, ipnr from attachment where type = 'wiki' and id = %s" pageAttachmentRes = cursor.execute(pageAttachmentQuery, (page, )) for attachment in pageAttachmentRes: thisAttachment = dict( zip([d[0] for d in pageAttachmentRes.description], attachment)) thisAttachment['fileobj'] = Attachment( self._env, 'wiki', page, thisAttachment['filename']).open() attachments.append(thisAttachment) baseQuery = 'select name, version, time, author, ipnr, text, comment, readonly from wiki where name = %s' res = cursor.execute(baseQuery, (page, )) wikiData = [] for row in res: wikiData.append(dict(zip([d[0] for d in res.description], row))) return wikiData, attachments def getWikiPageCurrent(self, page): '''Get the current version of a wiki page as a dict''' db = self._env.get_db_cnx() cursor = db.cursor() pageCountRes = cursor.execute( 'select count(*) as count from wiki where name = %s', (page, )) pageCount = pageCountRes.fetchone()[0] assert pageCount >= 1, 'Page %s not found in %s' % (page, self.name) pageQuery = 'select name, version, time, author, ipnr, text, comment, readonly from wiki where name = %s and version = (select max(version) from wiki where name = %s)' pageRes = cursor.execute(pageQuery, (page, page)) wikiPage = dict( zip([d[0] for d in pageRes.description], pageRes.fetchone())) wikiPage['attachment'] = [] pageAttachmentQuery = "select type, id, filename, size, time, description, author, ipnr from attachment where type = 'wiki' and id = %s" pageAttachmentRes = cursor.execute(pageAttachmentQuery, (page, )) for attachment in pageAttachmentRes: thisAttachment = dict( zip([d[0] for d in pageAttachmentRes.description], attachment)) thisAttachment['fileobj'] = Attachment( self._env, 'wiki', page, thisAttachment['filename']).open() wikiPage['attachment'].append(thisAttachment) return wikiPage def addWikiPage(self, page, attachments): '''Add a wiki page as a list of dictionaries''' db = self._env.get_db_cnx() cursor = db.cursor() pageCountRes = cursor.execute( 'select count(*) as count from wiki where name = %s', (page[0]['name'], )) pageCount = pageCountRes.fetchone()[0] assert pageCount == 0, 'Page %s found in %s' % (page[0]['name'], self.name) insertWikiQuery = 'insert into wiki (name, version, time, author, ipnr, text, comment, readonly) values (%s, %s, %s, %s, %s, %s, %s, %s)' for pV in page: insertValues = (pV['name'], pV['version'], pV['time'], pV['author'], pV['ipnr'], pV['text'], pV['comment'], pV['readonly']) insertRes = cursor.execute(insertWikiQuery, insertValues) for a in attachments: pageAttach = Attachment(self._env, 'wiki', pV['name']) pageAttach.description = a['description'] pageAttach.author = a['author'] pageAttach.ipnr = a['ipnr'] pageAttach.insert(a['filename'], a['fileobj'], a['size'], t=a['time']) db.commit() def getTicket(self, id): '''Get a ticket id as a dict''' db = self._env.get_db_cnx() cursor = db.cursor() idCountRes = cursor.execute( 'select count(*) as count from ticket where id = %s', (id, )) idCount = idCountRes.fetchone()[0] assert idCount >= 1, 'Page %s not found in %s' % (id, self.id) mainTicketQuery = 'select id, type, time, changetime, component, severity, priority, owner, \ reporter, cc, version, milestone, status, resolution, summary, description, keywords from ticket where id = %s' mainTicketRes = cursor.execute(mainTicketQuery, (id, )) ticket = dict( zip([d[0] for d in mainTicketRes.description], mainTicketRes.fetchone())) ticket['ticket_change'] = [] ticketChangeQuery = 'select time, author, field, oldvalue, newvalue from ticket_change where ticket = %s' ticketChangeRes = cursor.execute(ticketChangeQuery, (id, )) for ticket_change in ticketChangeRes: ticket['ticket_change'].append( dict( zip([d[0] for d in ticketChangeRes.description], ticket_change))) ticket['attachment'] = [] ticketAttachmentQuery = 'select type, id, filename, size, time, description, author, ipnr from attachment where type = \'ticket\' and id = %s' ticketAttachmentRes = cursor.execute(ticketAttachmentQuery, (id, )) for attachment in ticketAttachmentRes: thisAttachment = dict( zip([d[0] for d in ticketAttachmentRes.description], attachment)) thisAttachment['fileobj'] = Attachment( self._env, 'ticket', id, thisAttachment['filename']).open() ticket['attachment'].append(thisAttachment) return ticket def addTicket(self, ticket, source): '''Add a ticket from a dict''' db = self._env.get_db_cnx() cursor = db.cursor() idCountRes = cursor.execute( 'select count(*) as count from ticket where id = %s', (ticket['id'], )) idCount = idCountRes.fetchone()[0] assert idCount == 0, 'Ticket %s found in %s' % (ticket['id'], self.name) insertMainTicketQuery = 'insert into ticket (id, type, time, changetime, component, severity, priority, owner, \ reporter, cc, version, milestone, status, resolution, summary, description, keywords) \ values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)' insertMainTicketValues = (ticket['id'], ticket['type'], ticket['time'], ticket['changetime'], ticket['component'], \ ticket['severity'], ticket['priority'], ticket['owner'], ticket['reporter'], ticket['cc'], ticket['version'], \ ticket['milestone'], ticket['status'], ticket['resolution'], ticket['summary'], ticket['description'], ticket['keywords']) insertMainTicketRes = cursor.execute(insertMainTicketQuery, insertMainTicketValues) #so we know where the ticket came from insertTicketSourceQuery = 'insert into ticket_custom (ticket, name, value) values (%s, %s, %s)' insertTicketSourceValues = (ticket['id'], 'project', source) insertTicketSourceRes = cursor.execute(insertTicketSourceQuery, insertTicketSourceValues) insertTicketChangeQuery = 'insert into ticket_change (ticket, time, author, field, oldvalue, newvalue) values (%s, %s, %s, %s, %s, %s)' for ticket_change in ticket['ticket_change']: insertTicketChangeValues = (ticket['id'], ticket_change['time'], ticket_change['author'], ticket_change['field'], ticket_change['oldvalue'], ticket_change['newvalue']) insertTicketChangeRes = cursor.execute(insertTicketChangeQuery, insertTicketChangeValues) for a in ticket['attachment']: ticketAttach = Attachment(self._env, 'ticket', ticket['id']) ticketAttach.description = a['description'] ticketAttach.author = a['author'] ticketAttach.ipnr = a['ipnr'] ticketAttach.insert(a['filename'], a['fileobj'], a['size'], t=a['time']) db.commit() def getComponent(self, comp): '''Get a component as a dict''' db = self._env.get_db_cnx() cursor = db.cursor() compCountRes = cursor.execute( 'select count(*) as count from component where name = %s', (comp, )) compCount = compCountRes.fetchone()[0] assert compCount >= 1, 'Component %s not found in %s' % (comp, self.name) baseQuery = 'select name, owner, description from component where name = %s' res = cursor.execute(baseQuery, (comp, )) return (dict(zip([d[0] for d in res.description], res.fetchone()))) def addComponent(self, comp): '''Add a component from a dict''' db = self._env.get_db_cnx() cursor = db.cursor() assert comp['name'] != '', 'No name given' compCountRes = cursor.execute( 'select count(*) as count from component where name = %s', (comp['name'], )) compCount = compCountRes.fetchone()[0] if compCount > 0: 'Component %s found in %s. Skipping the re-insertion.' % ( comp['name'], self.name) else: insertComponentQuery = 'insert into component (name, owner, description) values (%s, %s, %s)' insertComponentValues = (comp['name'], comp['owner'], comp['description']) res = cursor.execute(insertComponentQuery, insertComponentValues) db.commit() def getMilestone(self, mile): '''Get a milestone as a dict''' db = self._env.get_db_cnx() cursor = db.cursor() mileCountRes = cursor.execute( 'select count(*) as count from milestone where name = %s', (mile, )) mileCount = mileCountRes.fetchone()[0] assert mileCount >= 1, 'Milestone %s not found in %s' % (mile, self.name) baseQuery = 'select name, due, completed, description from milestone where name = %s' res = cursor.execute(baseQuery, (mile, )) return (dict(zip([d[0] for d in res.description], res.fetchone()))) def addMilestone(self, mile): '''Add a milestone from a dict''' db = self._env.get_db_cnx() cursor = db.cursor() assert mile['name'] != '', 'No name given' mileCountRes = cursor.execute( 'select count(*) as count from milestone where name = %s', (mile['name'], )) mileCount = mileCountRes.fetchone()[0] if mileCount > 0: 'Milestone %s found in %s. Skipping the re-insertion.' % ( mile['name'], self.name) else: insertMilestoneQuery = 'insert into milestone (name, due, completed, description) values (%s, %s, %s, %s)' insertMilestoneValues = (mile['name'], mile['due'], mile['completed'], mile['description']) res = cursor.execute(insertMilestoneQuery, insertMilestoneValues) db.commit() def getEnum(self, enum): '''Get an enum as a dict. Enum should be a tupe of (name, type)''' db = self._env.get_db_cnx() cursor = db.cursor() enumCountRes = cursor.execute( 'select count(*) as count from enum where name = %s and type = %s', enum) enumCount = enumCountRes.fetchone()[0] assert enumCount >= 1, 'Enum %s not found in %s' % (enum, self.name) baseQuery = 'select name, type, value from enum where name = %s and type = %s' res = cursor.execute(baseQuery, enum) return (dict(zip([d[0] for d in res.description], res.fetchone()))) def addEnum(self, enum): '''Add a enum from a dict''' db = self._env.get_db_cnx() cursor = db.cursor() assert enum['name'] != '', 'No name given' enumCountRes = cursor.execute( 'select count(*) as count from enum where name = %s and type = %s', (enum['name'], enum['type'])) enumCount = enumCountRes.fetchone()[0] if enumCount > 0: print 'Enum %s found in %s. Skipping the re-insertion.' % ( enum['name'], self.name) else: insertEnumQuery = 'insert into enum (name, type, value) values (%s, %s, %s)' insertEnumValues = (enum['name'], enum['type'], enum['value']) res = cursor.execute(insertEnumQuery, insertEnumValues) db.commit() def getVersion(self, version): '''Get a version as a dict''' db = self._env.get_db_cnx() cursor = db.cursor() versionCountRes = cursor.execute( 'select count(*) as count from version where name = %s', (version, )) versionCount = versionCountRes.fetchone()[0] assert versionCount >= 1, 'Version %s not found in %s' % (version, self.name) baseQuery = 'select name, time, description from version where name = %s' res = cursor.execute(baseQuery, (version, )) return (dict(zip([d[0] for d in res.description], res.fetchone()))) def addVersion(self, version): '''Add a version from a dict''' db = self._env.get_db_cnx() cursor = db.cursor() assert version['name'] != '', 'No name given' versionCountRes = cursor.execute( 'select count(*) as count from version where name = %', (version['name'], )) versionCount = versionCountRes.fetchone()[0] if versionCount > 0: print 'Version %s found in %s. Skipping the re-insertion.' % ( version['name'], self.name) else: insertVersionQuery = 'insert into version (name, time, description) values (%s, %s, %s)' insertVersionValues = (version['name'], version['time'], version['description']) res = cursor.execute(insertVersionQuery, insertVersionValues) db.commit() def getRepository(self): '''Get the repository info, particularly the path and type''' repository = {} repository['type'] = self._env.config.get('trac', 'repository_type') repository['dir'] = self._env.config.get('trac', 'repository_dir') return repository def addRepository(self, repository): '''Add a repository from a dict specifying name, type and dir. This adds using the multiple repository functionality.''' assert repository.has_key('name') and repository.has_key( 'type') and repository.has_key( 'dir'), "Repository info not specified" self._env.config.set('repositories', '%s.dir' % repository['name'], repository['dir']) if repository['type'] == 'svn': repotype = 'direct-svnfs' else: repotype = repository['type'] self._env.config.set('repositories', '%s.type' % repository['name'], repotype) self._env.config.save()
class Client(object): def __init__(self, env_path): self.env_path = env_path self.env = Environment(env_path) self.db_cnx = self.env.get_db_cnx() self._registered_users_logins = [] def get_project_description(self): return self.env.project_description def get_users(self): result = self.env.get_known_users() trac_users = list([]) for user in result: user_login = user[0].lower() if user_login in self._registered_users_logins: continue u = TracUser(user_login) u.email = user[2] trac_users.append(u) self._registered_users_logins.append(user_login) # if we accept only authorised users, we don't have any more users to return # all of them were returned by "get_known_users" method if not tracLib.ACCEPT_NON_AUTHORISED_USERS: return trac_users # here we must to get component owners, issue reporters, owners and attachment authors # that are not registered users user_fields = [("owner", "component"), ("reporter", "ticket"), ("owner", "ticket"), ("author", "attachment")] first = True request = "" for column_name, table_name in user_fields: if first: first = False else: request += "UNION " request += "SELECT DISTINCT lower(%s) FROM %s " % (column_name, table_name) cursor = self.db_cnx.cursor() cursor.execute(request) for row in cursor: if row[0] not in self._registered_users_logins: trac_user = self._get_non_authorised_user(row[0]) if trac_user is not None: trac_users.append(trac_user) self._registered_users_logins.append(trac_user.name) return trac_users def _get_non_authorised_user(self, user_name): if user_name is None: return None # non authorized users in trac are stored like this "name <email_address>" start = user_name.find("<") end = user_name.rfind(">") # we don't accept users who didn't leave the email if (start > -1) and (end > start + 1): if user_name.find("@", start, end) > 0: user = TracUser(user_name[start + 1:end].replace(" ", "_")) user.email = user_name[start + 1:end].replace(" ", "_") return user return None def _get_user_login(self, user_name): if user_name is None: return None if user_name in self._registered_users_logins: return user_name if not tracLib.ACCEPT_NON_AUTHORISED_USERS: return None user = self._get_non_authorised_user(user_name) if (user is None) or (user.name not in self._registered_users_logins): return None return user.name def get_severities(self): return self._get_data_from_enum("severity") def get_issue_types(self): return self._get_data_from_enum("ticket_type") def get_issue_priorities(self): return self._get_data_from_enum("priority") def get_issue_resolutions(self): return [ TracResolution(name) for name in self._get_data_from_enum("resolution") ] def get_components(self): cursor = self.db_cnx.cursor() cursor.execute("SELECT name, owner, description FROM component") trac_components = list([]) for row in cursor: component = TracComponent(row[0]) component.owner = self._get_user_login(component.owner) if row[2] is not None: component.description = row[2] trac_components.append(component) return trac_components def get_versions(self): cursor = self.db_cnx.cursor() cursor.execute("SELECT name, time, description FROM version") trac_versions = list([]) for row in cursor: version = TracVersion(row[0]) if row[1]: version.time = self.to_unix_time(row[1]) if row[2] is not None: version.description = row[2] trac_versions.append(version) return trac_versions def get_issues(self): cursor = self.db_cnx.cursor() cursor.execute( "SELECT id, type, time, changetime, component, severity, priority, owner, reporter," "cc, version, status, resolution, summary, description, keywords FROM ticket" ) trac_issues = list([]) for row in cursor: issue = TracIssue(row[0]) issue.time = self.to_unix_time(row[2]) issue.changetime = self.to_unix_time(row[3]) issue.reporter = self._get_user_login(row[8]) if row[9] is not None: cc = row[9].split(",") for c in cc: if len(c) > 0: cc_name = self._get_user_login(c.strip()) if cc_name is not None: issue.cc.add(cc_name) issue.summary = row[13] issue.description = row[14] issue.custom_fields["Type"] = row[1] issue.custom_fields["Component"] = row[4] issue.custom_fields["Severity"] = row[5] issue.custom_fields["Priority"] = row[6] issue.custom_fields["Owner"] = self._get_user_login(row[7]) issue.custom_fields["Version"] = row[10] issue.custom_fields["Status"] = row[11] issue.custom_fields["Resolution"] = row[12] if row[15] is not None: keywords = row[15].rsplit(",") for kw in keywords: if len(kw) > 0: issue.keywords.add(kw.strip()) #getting custom fields from ticket_custom table custom_field_cursor = self.db_cnx.cursor() custom_field_cursor.execute( "SELECT name, value FROM ticket_custom WHERE ticket=%s", (str(row[0]), )) for cf in custom_field_cursor: issue.custom_fields[cf[0].capitalize()] = cf[1] # getting attachments from attachment table attachment_cursor = self.db_cnx.cursor() attachment_cursor.execute( "SELECT filename, size, time, description, author FROM attachment WHERE " "type = %s AND id = %s", ("ticket", str(issue.id))) #path = self.env_path + "/attachments/ticket/" + str(issue.id) + "/" for elem in attachment_cursor: #at = TracAttachment(path + elem[0]) at = TracAttachment( Attachment._get_path(self.env.path, 'ticket', str(issue.id), elem[0])) at.name = elem[0] at.size = elem[1] at.time = self.to_unix_time(elem[2]) at.description = elem[3] at.author_name = elem[4] issue.attachment.add(at) trac_issues.append(issue) #getting comments change_cursor = self.db_cnx.cursor() change_cursor.execute( "SELECT time, author, newvalue, oldvalue FROM ticket_change WHERE ticket = %s AND field = %s ORDER BY time DESC", ( str(row[0]), "comment", )) for elem in change_cursor: if (elem[2] is None) or (not len(elem[2].lstrip())): continue comment = TracComment(self.to_unix_time(elem[0])) comment.author = str(elem[1]) comment.content = unicode(elem[2]) comment.id = elem[3] issue.comments.add(comment) return trac_issues def get_custom_fields_declared(self): ini_file_path = self.env_path + "/conf/trac.ini" parser = ConfigParser() parser.read(ini_file_path) if not ("ticket-custom" in parser.sections()): return set([]) result = parser.items("ticket-custom") items = dict([]) for elem in result: items[elem[0]] = elem[1] keys = items.keys() custom_fields = list([]) for k in keys: if not ("." in k): field = TracCustomFieldDeclaration(k.capitalize()) field.type = items[k] options_key = k + ".options" if options_key in items: opts_str = items[options_key] opts = opts_str.rsplit("|") for o in opts: field.options.append(o) value_key = k + ".value" if value_key in items: field.value = items[value_key] label_key = k + ".label" if label_key in items: field.label = items[label_key] custom_fields.append(field) return custom_fields def _get_data_from_enum(self, type_name): cursor = self.db_cnx.cursor() cursor.execute("SELECT name, value FROM enum WHERE type=%s", (type_name, )) return [row[0] for row in cursor] def to_unix_time(self, time): return time / 1000
class TracDatabase(object): def __init__(self, project_name, path, db, host, user, password, append): self.env = Environment(path) self._append = append self._tracdb = self.env.get_db_cnx() self._tracdb.autocommit = False self._trac_cursor = self._tracdb.cursor() self._mantis_con = MySQLdb.connect( host=host, user=user, passwd=password, db=db, compress=1, cursorclass=MySQLdb.cursors.DictCursor, use_unicode=1) self._mantis_cursor = self._mantis_con.cursor() sql = "SELECT id FROM mantis_project_table WHERE name = %s" % ( project_name) print sql self.mantisCursor().execute( "SELECT id FROM mantis_project_table WHERE name = %s", (project_name)) result = self.mantisCursor().fetchall() if len(result) > 1: raise Exception("Ambiguous project name %s" % project_name) elif len(result) == 0: sql = """INSERT INTO mantis_project_table (name) VALUES (%s)""" % ( project_name) print sql self.mantisCursor().execute( """INSERT INTO mantis_project_table (name) VALUES (%s)""", (project_name)) self.mantisCommit() self._project_id = int(self.mantisCursor().lastrowid) else: self._project_id = int(result[0]['id']) self._bug_map = {} self._user_map = {} self._category_map = {} def projectId(self): return self._project_id def tracCursor(self): return self._trac_cursor def tracCommit(self): self._tracdb.commit() def mantisCursor(self): return self._mantis_cursor def mantisCommit(self): self._mantis_con.commit() def hasTickets(self): c = self.mantisCursor() c.execute('''SELECT count(*) FROM mantis_bug_table WHERE 1''') return int(c.fetchall()[0]['count(*)']) > 0 def clean(self, tablename): print 'TRUNCATE %s' % tablename self.mantisCursor().execute('TRUNCATE %s' % tablename) self.mantisCommit() def assertNoTickets(self): if not self._append and self.hasTickets(): raise Exception("Will not modify database with existing tickets!") return # generate a random character string of given length def generateCookie(self, length): password = '' for i in range(int(length)): password += random.choice("abcdefghijklmnopqrstuvwxyz0123456789") return password # generate a random character string of given length def generatePassword(self, length): password = '' for i in range(int(length)): password += chr(random.randint(33, 126)) return password def newBugId(self, tracId, mantisId): self._bug_map[tracId] = mantisId def bugId(self, tracId): return self._bug_map[tracId] def userId(self, username): if username == '' or username is None: return 0 if username not in self._user_map: sql = """SELECT id, username FROM mantis_user_table WHERE username = %s""" % ( username) print sql self.mantisCursor().execute( """SELECT id, username FROM mantis_user_table WHERE username = %s""", (username)) result = self.mantisCursor().fetchall() print result if result: self._user_map[username] = int(result[0]['id']) else: result = ((1)) while result: cookie = self.generateCookie(64) print cookie self.mantisCursor().execute( """SELECT cookie_string FROM mantis_user_table WHERE cookie_string = %s""", (cookie)) result = self.mantisCursor().fetchall() sql = """INSERT INTO mantis_user_table (username, realname, email, password, cookie_string) VALUES (%s, %s, %s, Md5(%s), %s) """ % ( username, NN_NAME, NN_EMAIL, self.generatePassword(16), cookie) print sql self.mantisCursor().execute( """INSERT INTO mantis_user_table (username, realname, email, password, cookie_string) VALUES (%s, %s, %s, MD5(%s), %s) """, (username, NN_NAME, NN_EMAIL, str( self.generatePassword(16)), str(cookie))) self.mantisCommit() self._user_map[username] = int(self.mantisCursor().lastrowid) return self._user_map[username] def categoryId(self, category): if category not in self._category_map: sql = """SELECT id FROM mantis_category_table WHERE name = %s AND project_id = '%d'""" % ( category, int(self.projectId())) print sql self.mantisCursor().execute( """SELECT id FROM mantis_category_table WHERE name = %s AND project_id = %s""", (category, self.projectId())) result = self.mantisCursor().fetchall() if result: self._category_map[category] = result[0]['id'] else: sql = """INSERT INTO mantis_category_table (project_id, name) VALUES (%s, %s) """ % (self.projectId(), category) print sql self.mantisCursor().execute( """INSERT INTO mantis_category_table (project_id, name) VALUES (%s, %s) """, (self.projectId(), category)) self.mantisCommit() self._category_map[category] = self.mantisCursor().lastrowid return self._category_map[category] def convertMantisTime(self, time2): time2 = datetime.fromtimestamp(time2) return long(str(int(time.mktime(time2.timetuple()))) + '000000') def convertTracTime(self, time2): time2 = time2 / 1000000 return time2
def update_tracenv_userdata(self, req, path, userdata): """Update the userdata in the specified environment using the records passed by userdata. @param path : path to the trac environment to update @param userdata : collection of userdata as returned from merge() @return success : boolean @return msg : details """ sql = [] exists = '' msg = '' envpath, tracenv = os.path.split(path) self.env.log.debug('Updating userdata in environment %s' % (path, )) dryrun = self.env.config.getbool('user_sync', 'dryrun', True) if not dryrun: self.env.log.debug('HOT!!! We are NOT in dryrun mode!') else: self.env.log.debug('TESTING - we ARE in dryrun mode.') try: env = Environment(path) except IOError: self.env.log.debug('Could not initialize environment at %s' % (path, )) return False, 'Could not initialize environment at %s' % (path, ) perm = PermissionSystem(env) if not 'TRAC_ADMIN' in perm.get_user_permissions(req.perm.username): raise PermissionError db = env.get_db_cnx() cursor = db.cursor() if not dryrun: self.env.log.debug('Updating database for %s' % (tracenv, )) for user in userdata: authenticated = userdata[user]['authenticated'] or 0 for att in userdata[user]: if att in ['path', 'authenticated', 'last_visit']: continue cursor.execute( "SELECT value FROM session_attribute WHERE sid='%s' AND name='%s' AND authenticated=%s" % ( user, att, authenticated, )) for row in cursor: exists = row[0] if exists: if exists == userdata[user][att]: continue if not dryrun: cursor.execute( "UPDATE session_attribute SET value='%s' WHERE sid='%s' AND name='%s' AND authenticated=%s;\n" % ( userdata[user][att], user, att, authenticated, )) sql.append( "UPDATE session_attribute SET value='%s' WHERE sid='%s' AND name='%s' AND authenticated=%s;\n" % ( userdata[user][att], user, att, authenticated, )) else: if not dryrun: cursor.execute( "INSERT INTO session_attribute (sid,authenticated,name,value) VALUES('%s',%s,'%s','%s');\n" % (user, authenticated, att, userdata[user][att])) sql.append( "INSERT INTO session_attribute (sid,authenticated,name,att) VALUES('%s',%s,'%s','%s');\n" % (user, authenticated, att, userdata[user][att])) if len(sql): if not dryrun: db.commit() sql_file_path = self.env.config.get( 'user_sync', 'sql_file_path') or os.path.join( self.env.path, 'log') if sql_file_path.lower() == 'none': self.env.log.debug( 'SQLFile disabled (sql_file_path is "none")') else: sqlfile = '%s.sql' % (tracenv, ) sqlfile = os.path.join(sql_file_path, sqlfile) try: if os.path.exists(sqlfile): os.unlink(sqlfile) self.env.log.debug('Writing SQL to %s' % (sqlfile, )) f = open(sqlfile, 'a') f.write('--- SQL for Trac environment %s\n' % (tracenv, )) f.writelines(sql) f.close() except IOError: self.env.log.debug('Could not write SQL file %s!' % (sqlfile, )) return False, 'Could not write SQL file %s!' % (sqlfile, ) except ValueError: self.env.log.debug('No value for sqlfile?') if dryrun: msg = 'Wrote SQL for Trac environment %s to %s' % ( tracenv, sqlfile, ) else: msg = 'Updated userdata in environment %s. SQL was additionally written to %s' % ( tracenv, sqlfile, ) else: msg = 'No updates for Trac environment %s' % (tracenv) self.env.log.debug('Done updating userdata in environment %s' % (path, )) return True, msg
from acct_mgr.pwhash import HtPasswdHashMethod, HtDigestHashMethod env = Environment(sys.argv[1]) store = AccountManager(env).password_store if isinstance(store, HtPasswdStore): env.config.set('account-manager', 'hash_method', 'HtPasswdHashMethod') prefix = '' elif isinstance(store, HtDigestStore): env.config.set('account-manager', 'hash_method', 'HtDigestHashMethod') prefix = store.realm + ':' else: print >> sys.stderr, 'Unsupported password store:', store.__class__.__name__ sys.exit(1) password_file = os.path.join( env.path, env.config.get('account-manager', 'password_file')) hashes = [line.strip().split(':', 1) for line in open(password_file)] hashes = [(u, p) for u, p in hashes if p.startswith(prefix)] if hashes: db = env.get_db_cnx() cursor = db.cursor() cursor.executemany( "INSERT INTO session_attribute " "(sid,authenticated,name,value) " "VALUES (%s,1,'password',%s)", hashes) db.commit() env.config.set('account-manager', 'password_store', 'SessionStore') env.config.save()
class TracDatabase(object): def __init__(self, path): self.env = Environment(path) self._db = self.env.get_db_cnx() self._db.autocommit = False self.loginNameCache = {} self.fieldNameCache = {} from trac.db.api import DatabaseManager self.using_postgres = DatabaseManager( self.env).connection_uri.startswith("postgres:") def db(self): return self._db def hasTickets(self): c = self.db().cursor() c.execute("SELECT count(*) FROM ticket") return int(c.fetchall()[0][0]) > 0 def assertNoTickets(self): if self.hasTickets(): raise Exception("Will not modify database with existing tickets!") def setSeverityList(self, s): """Remove all severities, set them to `s`""" self.assertNoTickets() c = self.db().cursor() c.execute("DELETE FROM enum WHERE type='severity'") for value, i in s: print " inserting severity '%s' - '%s'" % (value, i) c.execute( """INSERT INTO enum (type, name, value) VALUES (%s, %s, %s)""", ("severity", value, i)) self.db().commit() def setPriorityList(self, s): """Remove all priorities, set them to `s`""" self.assertNoTickets() c = self.db().cursor() c.execute("DELETE FROM enum WHERE type='priority'") for value, i in s: print " inserting priority '%s' - '%s'" % (value, i) c.execute( """INSERT INTO enum (type, name, value) VALUES (%s, %s, %s)""", ("priority", value, i)) self.db().commit() def setComponentList(self, l, key): """Remove all components, set them to `l`""" self.assertNoTickets() c = self.db().cursor() c.execute("DELETE FROM component") for comp in l: print " inserting component '%s', owner '%s'" % \ (comp[key], comp['owner']) c.execute("INSERT INTO component (name, owner) VALUES (%s, %s)", (comp[key], comp['owner'])) self.db().commit() def setVersionList(self, v, key): """Remove all versions, set them to `v`""" self.assertNoTickets() c = self.db().cursor() c.execute("DELETE FROM version") for vers in v: print " inserting version '%s'" % (vers[key]) c.execute("INSERT INTO version (name) VALUES (%s)", (vers[key], )) self.db().commit() def setMilestoneList(self, m, key): """Remove all milestones, set them to `m`""" self.assertNoTickets() c = self.db().cursor() c.execute("DELETE FROM milestone") for ms in m: milestone = ms[key] print " inserting milestone '%s'" % (milestone) c.execute("INSERT INTO milestone (name) VALUES (%s)", (milestone, )) self.db().commit() def addTicket(self, id, time, changetime, component, severity, priority, owner, reporter, cc, version, milestone, status, resolution, summary, description, keywords, customfields): c = self.db().cursor() desc = description type = "defect" if SEVERITIES: if severity.lower() == "enhancement": severity = "minor" type = "enhancement" else: if priority.lower() == "enhancement": priority = "minor" type = "enhancement" if PREFORMAT_COMMENTS: desc = '{{{\n%s\n}}}' % desc if REPLACE_BUG_NO: if BUG_NO_RE.search(desc): desc = re.sub(BUG_NO_RE, BUG_NO_REPL, desc) if PRIORITIES_MAP.has_key(priority): priority = PRIORITIES_MAP[priority] print " inserting ticket %s -- %s" % (id, summary) c.execute( """INSERT INTO ticket (id, type, time, changetime, component, severity, priority, owner, reporter, cc, version, milestone, status, resolution, summary, description, keywords) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""", (id, type, datetime2epoch(time), datetime2epoch(changetime), component, severity, priority, owner, reporter, cc, version, milestone, status.lower(), resolution, summary, desc, keywords)) self.db().commit() if self.using_postgres: c.execute("""SELECT SETVAL('ticket_id_seq', MAX(id)) FROM ticket; SELECT SETVAL('report_id_seq', MAX(id)) FROM report""") ticket_id = self.db().get_last_id(c, 'ticket') # add all custom fields to ticket for name, value in customfields.iteritems(): self.addTicketCustomField(ticket_id, name, value) return ticket_id def addTicketCustomField(self, ticket_id, field_name, field_value): c = self.db().cursor() if field_value == None: return c.execute( """INSERT INTO ticket_custom (ticket, name, value) VALUES (%s, %s, %s)""", (ticket_id, field_name, field_value)) self.db().commit() def addTicketComment(self, ticket, time, author, value): comment = value if PREFORMAT_COMMENTS: comment = '{{{\n%s\n}}}' % comment if REPLACE_BUG_NO: if BUG_NO_RE.search(comment): comment = re.sub(BUG_NO_RE, BUG_NO_REPL, comment) c = self.db().cursor() c.execute( """INSERT INTO ticket_change (ticket, time, author, field, oldvalue, newvalue) VALUES (%s, %s, %s, %s, %s, %s)""", (ticket, datetime2epoch(time), author, 'comment', '', comment)) self.db().commit() def addTicketChange(self, ticket, time, author, field, oldvalue, newvalue): c = self.db().cursor() if field == "owner": if LOGIN_MAP.has_key(oldvalue): oldvalue = LOGIN_MAP[oldvalue] if LOGIN_MAP.has_key(newvalue): newvalue = LOGIN_MAP[newvalue] if field == "priority": if PRIORITIES_MAP.has_key(oldvalue.lower()): oldvalue = PRIORITIES_MAP[oldvalue.lower()] if PRIORITIES_MAP.has_key(newvalue.lower()): newvalue = PRIORITIES_MAP[newvalue.lower()] # Doesn't make sense if we go from highest -> highest, for example. if oldvalue == newvalue: return c.execute( """INSERT INTO ticket_change (ticket, time, author, field, oldvalue, newvalue) VALUES (%s, %s, %s, %s, %s, %s)""", (ticket, datetime2epoch(time), author, field, oldvalue, newvalue)) self.db().commit() def addAttachment(self, author, a): if a['filename'] != '': description = a['description'] id = a['bug_id'] filename = a['filename'] filedata = StringIO.StringIO(a['thedata']) filesize = len(filedata.getvalue()) time = a['creation_ts'] print " ->inserting attachment '%s' for ticket %s -- %s" % \ (filename, id, description) attachment = Attachment(self.env, 'ticket', id) attachment.author = author attachment.description = description attachment.insert(filename, filedata, filesize, datetime2epoch(time)) del attachment def getLoginName(self, cursor, userid): if userid not in self.loginNameCache: cursor.execute("SELECT * FROM profiles WHERE userid = %s", (userid)) loginName = cursor.fetchall() if loginName: loginName = loginName[0]['login_name'] else: print """WARNING: unknown bugzilla userid %d, recording as anonymous""" % (userid) loginName = "anonymous" loginName = LOGIN_MAP.get(loginName, loginName) self.loginNameCache[userid] = loginName return self.loginNameCache[userid] def getFieldName(self, cursor, fieldid): if fieldid not in self.fieldNameCache: # fielddefs.fieldid got changed to fielddefs.id in Bugzilla # 2.23.3. if BZ_VERSION >= 2233: cursor.execute("SELECT * FROM fielddefs WHERE id = %s", (fieldid)) else: cursor.execute("SELECT * FROM fielddefs WHERE fieldid = %s", (fieldid)) fieldName = cursor.fetchall() if fieldName: fieldName = fieldName[0]['name'].lower() else: print "WARNING: unknown bugzilla fieldid %d, \ recording as unknown" % (userid) fieldName = "unknown" self.fieldNameCache[fieldid] = fieldName return self.fieldNameCache[fieldid]
def emailer(req, fromPage,name, fromAddr, toAddr, subject, msg,jsoncallback): """Perform sanity/security checks, look up usernames from trac and send message as [email protected]. req = CGI name = Friendly from = email address """ res = {} # bar access to everyone but this server #req.add_common_vars() #env_vars = req.subprocess_env.copy() #env_vars[''] config = loadConfig(req) text = msg.replace('%0A','\n') html = msg.replace('%0A','<br />') config['from'] = fromAddr config['name'] = name config['subject'] = subject list = [] addresses = toAddr.split(',') for name in addresses: if not validateEmail(name): # look up DB env = Environment(config['tracRendersEnv']) db = env.get_db_cnx() cursor = db.cursor() sql = "SELECT value from session_attribute where sid = '%s' and name = 'email'" % name cursor.execute(sql) db.commit() for row in cursor: list.append(row[0]) else: list.append(name) config['smtpserver'] = smtplib.SMTP(config['smtpserver']) # config['smtpserver'] = smtplib.SMTP('outbound.mailhop.org') config['smtpserver'].set_debuglevel(1) # config['smtpserver'].login('modfilms','f@milyman') toAddrFiltered = ','.join(list) textMsg = """ This was sent from http://%s %s says "%s" Powered by http://modfilms.net | Contact us at [email protected] """ % (config['httpServer'] + fromPage, config['name'], text) htmlMsg = """ <html> <head> <link rel="stylesheet" href="http://modfilms.com/js/themes/flora/flora.all.css" type="text/css" media="screen" title="Flora (Default)" /> <link rel="stylesheet" href="http://modfilms.com/js/demos/css/style.css" type="text/css" /> </head> <body> <p>This was sent from <a href="%s">http://%s</a></p> <p>%s says: </p> <p><i>"%s"</i></p> <p>Email <a href="mailto:[email protected]">[email protected]</a> if you need assistance</p> <p><a href="http://modfilms.net"><img border="0" src="http://modfilms.com/images/poweredby.gif" alt="Powered by the MOD Films network"></p> </body> </html> """ % (config['httpServer'] + fromPage,config['httpServer'] + fromPage,config['name'], html) # theMsg = createhtmlmail(htmlMsg, textMsg, subject) theMsg = createtextmail(textMsg,subject) SENDER = config['from'] RECIPIENT = toAddrFiltered headers = "From: %s\r\nTo: %s\r\n" % (SENDER, RECIPIENT) message = headers + theMsg try: smtpresult = config['smtpserver'].sendmail(SENDER, RECIPIENT, message) if smtpresult: errstr = "" for recip in smtpresult.keys(): errstr = """Could not delivery mail to: %s Server said: %s %s %s""" % (recip, smtpresult[recip][0], smtpresult[recip][1], errstr) raise smtplib.SMTPException, errstr config['smtpserver'].quit() res['err'] = 'Email sent' res['good'] = True except smtplib.SMTPRecipientsRefused, recipients: res['err'] = 'Message not sent. Check the email addresses or studio usernames are valid.' res['good'] = False
class BuildDeleter(object): """Class for deleting a build.""" def __init__(self, env_path): self.env = Environment(env_path) self.logs_dir = self.env.config.get('bitten', 'logs_dir', 'log/bitten') def _log_files(self, cursor, build): """Return a list of log files.""" cursor.execute("SELECT filename FROM bitten_log WHERE build=%s", (build, )) rows = cursor.fetchall() all_files = [] for row in rows: filename = row[0] file_prefix = os.path.join(self.logs_dir, filename) for suffix in ['', '.level', '.levels']: log_file = file_prefix + suffix if os.path.isfile(log_file): all_files.append(log_file) return all_files def discover(self, build): """Print a summary of what is linked to the build.""" print "Items to delete for build %r" % (build, ) print "-------------------------------" db = self.env.get_db_cnx() cursor = db.cursor() print "Attachments for build resource:" cursor.execute("SELECT config FROM bitten_build WHERE id=%s", (build, )) config = cursor.fetchone()[0] print " %s/%s" % (config, build) print "Log files:" print " ", "\n ".join(self._log_files(cursor, build)) print "Rows from bitten_log with ids:" cursor.execute("SELECT id FROM bitten_log WHERE build=%s", (build, )) print " ", "\n ".join(str(row[0]) for row in cursor.fetchall()) print "Rows from bitten_report with ids:" cursor.execute("SELECT id FROM bitten_report WHERE build=%s", (build, )) print " ", "\n ".join(str(row[0]) for row in cursor.fetchall()) print "Rows from bitten_report_item with report set to these ids will" print "also be deleted." print "Rows from bitten_step for this build with names:" cursor.execute("SELECT name FROM bitten_step WHERE build=%s", (build, )) print " ", "\n ".join(str(row[0]) for row in cursor.fetchall()) print "Row from bitten_build with id:" cursor.execute("SELECT id FROM bitten_build WHERE id=%s", (build, )) print " ", "\n ".join(str(row[0]) for row in cursor.fetchall()) def remove(self, build): """Delete what is linked to the build.""" print "Deleting items for build %r" % (build, ) db = self.env.get_db_cnx() cursor = db.cursor() print "Determining associated config." cursor.execute("SELECT config FROM bitten_build WHERE id=%s", (build, )) config = cursor.fetchone()[0] print "Collecting log files." filenames = self._log_files(cursor, build) try: print "Deleting bitten_log entries." cursor.execute("DELETE FROM bitten_log WHERE build=%s", (build, )) print "Deleting bitten_report_item_entries." cursor.execute( "DELETE FROM bitten_report_item WHERE report IN (" "SELECT bitten_report.id FROM bitten_report " "WHERE bitten_report.build=%s" ")", (build, )) print "Deleting bitten_report entires." cursor.execute("DELETE FROM bitten_report WHERE build=%s", (build, )) print "Deleting bitten_step entries." cursor.execute("DELETE FROM bitten_step WHERE build=%s", (build, )) print "Delete bitten_build entry." cursor.execute("DELETE FROM bitten_build WHERE id=%s", (build, )) except: db.rollback() print "Build deletion failed. Database rolled back." raise print "Bitten database changes committed." db.commit() print "Removing log files." for filename in filenames: os.remove(filename) print "Removing attachments." resource = Resource('build', '%s/%s' % (config, build)) Attachment.delete_all(self.env, 'build', resource.id, db)
class TracDatabase(object): def __init__(self, project_name, path, db, host, user, password, append): self.env = Environment(path) self._append = append self._tracdb = self.env.get_db_cnx() self._tracdb.autocommit = False self._trac_cursor = self._tracdb.cursor() self._mantis_con = MySQLdb.connect(host=host, user=user, passwd=password, db=db, compress=1, cursorclass=MySQLdb.cursors.DictCursor, use_unicode=1) self._mantis_cursor = self._mantis_con.cursor() sql = "SELECT id FROM mantis_project_table WHERE name = %s" % (project_name) print sql self.mantisCursor().execute("SELECT id FROM mantis_project_table WHERE name = %s", (project_name)) result = self.mantisCursor().fetchall() if len(result) > 1: raise Exception("Ambiguous project name %s" % project_name) elif len(result) == 0: sql = """INSERT INTO mantis_project_table (name) VALUES (%s)""" % (project_name) print sql self.mantisCursor().execute("""INSERT INTO mantis_project_table (name) VALUES (%s)""" , (project_name)) self.mantisCommit() self._project_id = int(self.mantisCursor().lastrowid) else: self._project_id = int(result[0]['id']) self._bug_map = {} self._user_map = {} self._category_map = {} def projectId(self): return self._project_id def tracCursor(self): return self._trac_cursor def tracCommit(self): self._tracdb.commit() def mantisCursor(self): return self._mantis_cursor def mantisCommit(self): self._mantis_con.commit() def hasTickets(self): c = self.mantisCursor() c.execute('''SELECT count(*) FROM mantis_bug_table WHERE 1''') return int(c.fetchall()[0]['count(*)']) > 0 def clean(self, tablename): print 'TRUNCATE %s' % tablename self.mantisCursor().execute('TRUNCATE %s' % tablename) self.mantisCommit() def assertNoTickets(self): if not self._append and self.hasTickets(): raise Exception("Will not modify database with existing tickets!") return # generate a random character string of given length def generateCookie(self, length): password = '' for i in range(int(length)): password += random.choice("abcdefghijklmnopqrstuvwxyz0123456789") return password # generate a random character string of given length def generatePassword(self, length): password = '' for i in range(int(length)): password += chr(random.randint(33,126)) return password def newBugId(self, tracId, mantisId): self._bug_map[tracId] = mantisId def bugId(self, tracId): return self._bug_map[tracId] def userId(self, username): if username == '' or username is None: return 0 if username not in self._user_map: sql = """SELECT id, username FROM mantis_user_table WHERE username = %s""" % (username) print sql self.mantisCursor().execute("""SELECT id, username FROM mantis_user_table WHERE username = %s""" , (username)) result = self.mantisCursor().fetchall() print result if result: self._user_map[username] = int(result[0]['id']) else: result = ((1)) while result: cookie = self.generateCookie(64) print cookie self.mantisCursor().execute("""SELECT cookie_string FROM mantis_user_table WHERE cookie_string = %s""" , (cookie)) result = self.mantisCursor().fetchall() sql = """INSERT INTO mantis_user_table (username, realname, email, password, cookie_string) VALUES (%s, %s, %s, Md5(%s), %s) """ % (username, NN_NAME, NN_EMAIL, self.generatePassword(16), cookie) print sql self.mantisCursor().execute("""INSERT INTO mantis_user_table (username, realname, email, password, cookie_string) VALUES (%s, %s, %s, MD5(%s), %s) """ , (username, NN_NAME, NN_EMAIL, str(self.generatePassword(16)), str(cookie))) self.mantisCommit() self._user_map[username] = int(self.mantisCursor().lastrowid) return self._user_map[username] def categoryId(self, category): if category not in self._category_map: sql = """SELECT id FROM mantis_category_table WHERE name = %s AND project_id = '%d'""" % (category, int(self.projectId())) print sql self.mantisCursor().execute("""SELECT id FROM mantis_category_table WHERE name = %s AND project_id = %s""" , (category, self.projectId())) result = self.mantisCursor().fetchall() if result: self._category_map[category] = result[0]['id'] else: sql = """INSERT INTO mantis_category_table (project_id, name) VALUES (%s, %s) """ % (self.projectId(), category) print sql self.mantisCursor().execute("""INSERT INTO mantis_category_table (project_id, name) VALUES (%s, %s) """ , (self.projectId(), category)) self.mantisCommit() self._category_map[category] = self.mantisCursor().lastrowid return self._category_map[category] def convertMantisTime(self,time2): time2 = datetime.fromtimestamp(time2) return long(str(int(time.mktime(time2.timetuple()))) + '000000') def convertTracTime(self,time2): time2 = time2 / 1000000 return time2
def add_trac_to_project(application, smtp_enabled=True, privatecomments=True, sensitivetickets=True, batchmod=True, autocompleteusers=True, customfieldadmin=True, qafields=True, privatetickets=False, tracwysiwyg=True, attachment_max_size=10485760, milestones=[], tickets=[], project_name=u'', ): from penelope.core.models.dashboard import Project project = DBSession.query(Project).get(application.project_id) settings = get_current_registry().settings or application.settings tracenvs = settings.get('penelope.trac.envs') if not os.path.exists(tracenvs): # TODO: logging bootstrap os.mkdir(tracenvs) tracname = None idx = '' while (not tracname): tracname = idnormalizer.normalize("%s%s" % (project.id, idx)) trac_path = '%s/%s' % (tracenvs, tracname) if os.path.exists(trac_path): idx = idx and (idx+1) or 1 tracname = None trac_perm = { 'administrator': ['TRAC_ADMIN', 'EXTRA_TIMEENTRY'], 'customer': ['TICKET_CREATE', 'TICKET_MODIFY', 'TICKET_VIEW', 'WIKI_VIEW', 'XML_RPC', 'CHANGESET_VIEW', 'FILE_VIEW', 'LOG_VIEW', 'MILESTONE_VIEW', 'REPORT_VIEW', 'REPORT_SQL_VIEW', 'ROADMAP_VIEW', 'SEARCH_VIEW', 'TIMELINE_VIEW'], 'developer': ['TICKET_CREATE', 'TICKET_MODIFY', 'TICKET_VIEW', 'WIKI_VIEW', 'XML_RPC', 'WIKI_CREATE', 'WIKI_MODIFY', 'CHANGESET_VIEW', 'FILE_VIEW', 'LOG_VIEW', 'MILESTONE_VIEW', 'REPORT_VIEW', 'REPORT_SQL_VIEW', 'ROADMAP_VIEW', 'SEARCH_VIEW', 'TIMELINE_VIEW', 'REPORT_ADMIN'], 'internal_developer': ['developer', 'TRAC_ADMIN', 'TIME_ENTRY_ADD'], 'external_developer': ['developer'], 'project_manager': ['administrator', 'TIME_ENTRY_ADD'], } pordb = str(DBSession.bind.url) run([trac_path, 'initenv "%s" "%s?schema=trac_%s"' % ( tracname, pordb.replace('postgresql://', 'postgres://'), tracname)]) tracenv = Environment(trac_path) # REPORTS cnx = tracenv.get_db_cnx().cnx cursor = cnx.cursor() cursor.executemany(\ "INSERT INTO report (title, description, query) VALUES (%s, %s, %s)", get_reports(project_id=project.id)) cursor.close() cnx.commit() # remove report 2 cursor = cnx.cursor() cursor.execute("DELETE FROM report where id=2;") cursor.close() cnx.commit() # update reports cursor = cnx.cursor() cursor.execute("""UPDATE report set query=' SELECT p.value AS __color__, t.id AS ticket, summary, t.type AS type, cr.name AS CR, owner, status, time AS created, changetime AS _changetime, t.description AS _description, reporter AS _reporter FROM ticket t LEFT JOIN enum p ON p.name = t.priority AND p.type = ''priority'' LEFT JOIN ticket_custom tc ON t.id = tc.ticket LEFT JOIN public.customer_requests cr ON tc.value = cr.id WHERE status <> ''closed'' AND tc.name = ''customerrequest'' ORDER BY CAST(p.value AS int), milestone, t.type, time' where id=1;""") cursor.execute("""UPDATE report set query=' SELECT p.value AS __color__, ''Milestone ''||milestone AS __group__, t.id AS ticket, summary, t.type AS type, cr.name AS CR, owner, status, time AS created, changetime AS _changetime, t.description AS _description, reporter AS _reporter FROM ticket t LEFT JOIN enum p ON p.name = t.priority AND p.type = ''priority'' LEFT JOIN ticket_custom tc ON t.id = tc.ticket LEFT JOIN public.customer_requests cr ON tc.value = cr.id WHERE status <> ''closed'' AND tc.name = ''customerrequest'' ORDER BY (milestone IS NULL),milestone, CAST(p.value AS int), t.type, time' where id=3;""") cursor.execute("""UPDATE report set query=' SELECT p.value AS __color__, owner AS __group__, t.id AS ticket, summary, milestone, cr.name AS CR, t.type AS type, time AS created, changetime AS _changetime, t.description AS _description, reporter AS _reporter FROM ticket t LEFT JOIN enum p ON p.name = t.priority AND p.type = ''priority'' LEFT JOIN ticket_custom tc ON t.id = tc.ticket LEFT JOIN public.customer_requests cr ON tc.value = cr.id WHERE status = ''accepted'' AND tc.name = ''customerrequest'' ORDER BY owner, CAST(p.value AS int), t.type, time' where id=4;""") cursor.execute("""UPDATE report set query=' SELECT p.value AS __color__, owner AS __group__, t.id AS ticket, summary, milestone, t.type AS type, cr.name AS CR, time AS created, t.description AS _description_, changetime AS _changetime, reporter AS _reporter FROM ticket t LEFT JOIN enum p ON p.name = t.priority AND p.type = ''priority'' LEFT JOIN ticket_custom tc ON t.id = tc.ticket LEFT JOIN public.customer_requests cr ON tc.value = cr.id WHERE status = ''accepted'' AND tc.name = ''customerrequest'' ORDER BY owner, CAST(p.value AS int), t.type, time' where id=5;""") cursor.execute("""UPDATE report set query=' SELECT p.value AS __color__, (CASE status WHEN ''accepted'' THEN ''Accepted'' ELSE ''Owned'' END) AS __group__, t.id AS ticket, summary, milestone, cr.name AS CR, t.type AS type, priority, time AS created, changetime AS _changetime, t.description AS _description, reporter AS _reporter FROM ticket t LEFT JOIN enum p ON p.name = t.priority AND p.type = ''priority'' LEFT JOIN ticket_custom tc ON t.id = tc.ticket LEFT JOIN public.customer_requests cr ON tc.value = cr.id WHERE t.status <> ''closed'' AND owner = $USER AND tc.name = ''customerrequest'' ORDER BY (status = ''accepted'') DESC, CAST(p.value AS int), milestone, t.type, time' where id=7;""") cursor.execute("""UPDATE report set query=' SELECT p.value AS __color__, (CASE owner WHEN $USER THEN ''My Tickets'' ELSE ''Active Tickets'' END) AS __group__, t.id AS ticket, summary, milestone, t.type AS type, cr.name AS CR, owner, status, time AS created, changetime AS _changetime, t.description AS _description, reporter AS _reporter FROM ticket t LEFT JOIN enum p ON p.name = t.priority AND p.type = ''priority'' LEFT JOIN ticket_custom tc ON t.id = tc.ticket LEFT JOIN public.customer_requests cr ON tc.value = cr.id WHERE status <> ''closed'' AND tc.name = ''customerrequest'' ORDER BY (COALESCE(owner, '''') = $USER) DESC, CAST(p.value AS int), milestone, t.type, time' where id=8;""") cursor.close() cnx.commit() # remove default trac's milestones, components, versions cursor = cnx.cursor() cursor.execute("DELETE FROM milestone;") cursor.close() cnx.commit() cursor = cnx.cursor() cursor.execute("DELETE FROM component;") cursor.close() cnx.commit() cursor = cnx.cursor() cursor.execute("DELETE FROM version;") cursor.close() cnx.commit() # TODO: attualmente il riferimento dal trac al progetto dashboard è il project_id, # considerando un'instalalzzione che condicide lo stesso stack wsgi, # valutare se deve essere una uri (jsnorpc, xmlrpx, ...) # o un dsn che punti al db, o ... tracenv.config.set('por-dashboard', 'project-id', application.project_id) # custom templates templates = settings.get('penelope.trac.templates') masterconfig = settings.get('penelope.trac.masterconfig') if templates: tracenv.config.set('inherit', 'templates_dir', templates) # master config if masterconfig: tracenv.config.set('inherit', 'file', masterconfig) # set name and description tracenv.config.set('project', 'name', project_name) tracenv.config.set('project', 'descr', application.name) tracenv.config.set('notification', 'smtp_enabled', smtp_enabled and 'true' or 'false') tracenv.config.set('notification', 'always_notify_owner', 'true') tracenv.config.set('notification', 'always_notify_reporter', 'true') manager_email = project.manager.email or '' tracenv.config.set('notification', 'smtp_always_cc', manager_email) # manager should always receiv CC tracenv.config.set('attachment', 'max_size', attachment_max_size) tracenv.config.set('components', 'penelope.trac.*', 'enabled') tracenv.config.set('components', 'themeengine.admin.*', 'enabled') tracenv.config.set('components', 'themeengine.api.*', 'enabled') tracenv.config.set('components', 'themeengine.web_ui.*', 'enabled') tracenv.config.set('components', 'ticketrelations.*', 'enabled') tracenv.config.set('components', 'tracopt.perm.config_perm_provider.extrapermissionsprovider', 'enabled') # All the custom permission names are converted to uppercase. # It is not possible to have lowercase and distinguish them from the standard permissions. tracenv.config.set('extra-permissions', 'extra_timeentry', 'TIME_ENTRY_ADD') tracenv.config.set('theme','theme', 'por') # ticket-custom tracenv.config.set('ticket-custom', 'customerrequest', 'select') tracenv.config.set('ticket-custom', 'customerrequest.label', 'Customer Request') tracenv.config.set('ticket-custom', 'blocking', 'text') tracenv.config.set('ticket-custom', 'blocking.label', 'Blocking') tracenv.config.set('ticket-custom', 'blockedby', 'text') tracenv.config.set('ticket-custom', 'blockedby.label', 'Blocked By') # BBB: ii valori di customerrequest vengono caricati ondemand tracenv.config.set('ticket-custom', 'customerrequest.options', '') # see ticket:80 if qafields: tracenv.config.set('ticket-custom', 'issuetype', 'select') tracenv.config.set('ticket-custom', 'issuetype.label', 'Natura del problema') tracenv.config.set('ticket-custom', 'issuetype.options', '|'.join([u"", u"sistemistica", u"funzionalità", u"design (grafica, layout...)", u"prestazioni", u"mi aspettavo che..."])) tracenv.config.set('ticket-custom', 'esogeno', 'checkbox') tracenv.config.set('ticket-custom', 'esogeno.label', 'Ticket aperto dal Cliente') tracenv.config.set('ticket-custom', 'esogeno.value', 'false') tracenv.config.set('ticket-custom', 'stats_exclude', 'checkbox') tracenv.config.set('ticket-custom', 'stats_exclude.label', 'Exclude from report stats') tracenv.config.set('ticket-custom', 'stats_exclude.value', 'false') tracenv.config.set('ticket-custom', 'fasesviluppo', 'select') tracenv.config.set('ticket-custom', 'fasesviluppo.label', 'Fase sviluppo') tracenv.config.set('ticket-custom', 'fasesviluppo.options', '|'.join([u"", u"In lavorazione", u"Per lo staging", u"In staging", u"Per la produzione", u"In produzione"])) tracenv.config.set('ticket', 'restrict_owner', 'true') tracenv.config.set('ticket-custom', 'milestone.invalid_if', '') # WORKFLOW tracenv.config.set('ticket-workflow', 'accept', 'new,reviewing -> assigned') tracenv.config.set('ticket-workflow', 'accept.operations', 'set_owner_to_self') tracenv.config.set('ticket-workflow', 'accept.permissions', 'TICKET_MODIFY') tracenv.config.set('ticket-workflow', 'leave', '* -> *') tracenv.config.set('ticket-workflow', 'leave.default', '1') tracenv.config.set('ticket-workflow', 'leave.operations', 'leave_status') tracenv.config.set('ticket-workflow', 'reassign', 'new,assigned,accepted,reopened -> assigned') tracenv.config.set('ticket-workflow', 'reassign.operations', 'set_owner') tracenv.config.set('ticket-workflow', 'reassign.permissions', 'TICKET_MODIFY') tracenv.config.set('ticket-workflow', 'reassign_reviewing', 'reviewing -> *') tracenv.config.set('ticket-workflow', 'reassign_reviewing.name', 'reassign review') tracenv.config.set('ticket-workflow', 'reassign_reviewing.operations', 'set_owner') tracenv.config.set('ticket-workflow', 'reassign_reviewing.permissions', 'TICKET_MODIFY') tracenv.config.set('ticket-workflow', 'reopen', 'closed -> reopened') tracenv.config.set('ticket-workflow', 'reopen.operations', 'del_resolution') tracenv.config.set('ticket-workflow', 'reopen.permissions', 'TRAC_ADMIN') tracenv.config.set('ticket-workflow', 'resolve', 'new,assigned,reopened,reviewing -> closed') tracenv.config.set('ticket-workflow', 'resolve.operations', 'set_resolution') tracenv.config.set('ticket-workflow', 'resolve.permissions', 'TICKET_MODIFY') tracenv.config.set('ticket-workflow', 'review', 'new,assigned,reopened -> reviewing') tracenv.config.set('ticket-workflow', 'review.operations', 'set_owner') tracenv.config.set('ticket-workflow', 'review.permissions', 'TICKET_MODIFY') tracenv.config.set('milestone-groups', 'closed', 'closed') tracenv.config.set('milestone-groups', 'closed.order', '0') tracenv.config.set('milestone-groups', 'closed.query_args', 'group=resolution') tracenv.config.set('milestone-groups', 'closed.overall_completion', 'true') tracenv.config.set('milestone-groups', 'active', '*') tracenv.config.set('milestone-groups', 'active.order', '1') tracenv.config.set('milestone-groups', 'active.css_class', 'open') tracenv.config.set('milestone-groups', 'new', 'new,reopened') tracenv.config.set('milestone-groups', 'new.order', '2') # navigation tracenv.config.set('metanav', 'logout', 'disabled') # permissions tracenv.config.set('components', 'penelope.trac.users.*', 'enabled') tracenv.config.set('trac', 'permission_store', 'PorPermissionStore') tracenv.config.set('trac', 'show_email_addresses', 'true') # xmlrpc plugin tracenv.config.set('components', 'tracrpc.api.xmlrpcsystem', 'enabled') tracenv.config.set('components', 'tracrpc.xml_rpc.xmlrpcprotocol', 'enabled') tracenv.config.set('components', 'tracrpc.web_ui.rpcweb', 'enabled') tracenv.config.set('components', 'tracrpc.ticket.*', 'enabled') # DynamicFields Plugin tracenv.config.set('components', 'dynfields.rules.*','enabled') tracenv.config.set('components', 'dynfields.web_ui.*','enabled') # User & Roles (ReadOnly !!!) # tracenv.config.set('user_manager', 'user_store', 'PorUserStore') # tracenv.config.set('user_manager', 'attribute_provider', 'PorAttributeProvider') # BatchModifyPlugin if batchmod: tracenv.config.set('components', 'batchmod.web_ui.*', 'enabled') # Traccustomfieldadmin if customfieldadmin: tracenv.config.set('components', 'customfieldadmin.*', 'enabled') # PrivateCommentsPlugin if privatecomments: tracenv.config.set('components', 'privatecomments.privatecomments.*', 'enabled') # PrivateTicketPlugin if privatetickets: tracenv.config.set('components', 'privatetickets.policy.*', 'enabled') tracenv.config.set('trac', 'permission_policies', 'PrivateTicketsPolicy, %s' % tracenv.config.get('trac', 'permission_policies')) trac_perm['customer'].append('TICKET_VIEW_SELF') # SensitiveTicketsPlugin if sensitivetickets: tracenv.config.set('components', 'sensitivetickets.*', 'enabled') tracenv.config.set('trac', 'permission_policies', 'SensitiveTicketsPolicy, %s' % tracenv.config.get('trac', 'permission_policies')) tracenv.config.set('ticket-custom', 'sensitive.show_if_group', 'administrator|developer') # utilizzato se il default e' 1, se il default e' 0 non serve # tracenv.config.set('ticket-custom', 'sensitive.clear_on_hide', 'false') # tracenv.config.set('ticket-custom', 'sensitive.has_permission', 'SENSITIVE_VIEW') tracenv.config.set('ticket-custom', 'sensitive.value', '0') trac_perm['developer'].append('SENSITIVE_VIEW') # tracwysiwyg if tracwysiwyg: tracenv.config.set('components', 'tracwysiwyg.wysiwygmodule', 'enabled') # AutoCompleteUsers if autocompleteusers: tracenv.config.set('components', 'autocompleteusers.autocompleteusers', 'enabled') tracenv.config.set('wiki', 'max_size', 1048576) tracenv.config.set('logging', 'log_file', 'trac.log') tracenv.config.set('logging', 'log_level', 'INFO') tracenv.config.set('logging', 'log_type', 'file') tracenv.config.save() # let's remove notification config - it is set by the global config tracenv.config.remove('notification', 'smtp_from') tracenv.config.remove('notification', 'smtp_from_name') tracenv.config.remove('notification', 'replyto') tracenv.config.remove('notification', 'smtp_replyto') tracenv.config.remove('notification', 'email_sender') tracenv.config.remove('notification', 'smtp_enabled') tracenv.config.remove('notification', 'smtp_host') tracenv.config.remove('notification', 'smtp_port') tracenv.config.remove('notification', 'smtp_password') tracenv.config.remove('notification', 'smtp_username') tracenv.config.remove('trac', 'repository_sync_per_request') tracenv.config.save() run([trac_path, 'upgrade --no-backup']) run([trac_path, 'permission remove anonymous *']) run([trac_path, 'permission remove authenticated *']) for role, perms in trac_perm.items(): for perm in perms: run([trac_path, "permission add %s %s" % (role, perm)]) run([trac_path, "ticket_type add verification"]) # hack to minimize config size run([trac_path, 'config set browser color_scale True']) # add properly milestones milestones.append({'title': 'Backlog', 'due_date': date.today().replace(year=date.today().year+1)}) for milestone in milestones: due = milestone['due_date'] if due: due = milestone['due_date'].strftime('%Y-%m-%d') run([trac_path, 'milestone add "%s" %s' % (milestone['title'], due)]) else: run([trac_path, 'milestone add "%s"' % milestone['title']]) tracenv = Environment(trac_path) for ticket in tickets: # in this moment the customer request has a proper id ticket['status'] = 'new' t = Ticket(tracenv) t.populate(ticket) t.insert() application.api_uri = 'trac://%s' % tracname application.trac_name = tracname
class BuildDeleter(object): """Class for deleting a build.""" def __init__(self, env_path): self.env = Environment(env_path) self.logs_dir = self.env.config.get('bitten', 'logs_dir', 'log/bitten') def _log_files(self, cursor, build): """Return a list of log files.""" cursor.execute("SELECT filename FROM bitten_log WHERE build=%s", (build,)) rows = cursor.fetchall() all_files = [] for row in rows: filename = row[0] file_prefix = os.path.join(self.logs_dir, filename) for suffix in ['', '.level', '.levels']: log_file = file_prefix + suffix if os.path.isfile(log_file): all_files.append(log_file) return all_files def discover(self, build): """Print a summary of what is linked to the build.""" print "Items to delete for build %r" % (build,) print "-------------------------------" db = self.env.get_db_cnx() cursor = db.cursor() print "Attachments for build resource:" cursor.execute("SELECT config FROM bitten_build WHERE id=%s", (build,)) config = cursor.fetchone()[0] print " %s/%s" % (config, build) print "Log files:" print " ", "\n ".join(self._log_files(cursor, build)) print "Rows from bitten_log with ids:" cursor.execute("SELECT id FROM bitten_log WHERE build=%s", (build,)) print " ", "\n ".join(str(row[0]) for row in cursor.fetchall()) print "Rows from bitten_report with ids:" cursor.execute("SELECT id FROM bitten_report WHERE build=%s", (build,)) print " ", "\n ".join(str(row[0]) for row in cursor.fetchall()) print "Rows from bitten_report_item with report set to these ids will" print "also be deleted." print "Rows from bitten_step for this build with names:" cursor.execute("SELECT name FROM bitten_step WHERE build=%s", (build,)) print " ", "\n ".join(str(row[0]) for row in cursor.fetchall()) print "Row from bitten_build with id:" cursor.execute("SELECT id FROM bitten_build WHERE id=%s", (build,)) print " ", "\n ".join(str(row[0]) for row in cursor.fetchall()) def remove(self, build): """Delete what is linked to the build.""" print "Deleting items for build %r" % (build,) db = self.env.get_db_cnx() cursor = db.cursor() print "Determining associated config." cursor.execute("SELECT config FROM bitten_build WHERE id=%s", (build,)) config = cursor.fetchone()[0] print "Collecting log files." filenames = self._log_files(cursor, build) try: print "Deleting bitten_log entries." cursor.execute("DELETE FROM bitten_log WHERE build=%s", (build,)) print "Deleting bitten_report_item_entries." cursor.execute("DELETE FROM bitten_report_item WHERE report IN (" "SELECT bitten_report.id FROM bitten_report " "WHERE bitten_report.build=%s" ")", (build,)) print "Deleting bitten_report entires." cursor.execute("DELETE FROM bitten_report WHERE build=%s", (build,)) print "Deleting bitten_step entries." cursor.execute("DELETE FROM bitten_step WHERE build=%s", (build,)) print "Delete bitten_build entry." cursor.execute("DELETE FROM bitten_build WHERE id=%s", (build,)) except: db.rollback() print "Build deletion failed. Database rolled back." raise print "Bitten database changes committed." db.commit() print "Removing log files." for filename in filenames: os.remove(filename) print "Removing attachments." resource = Resource('build', '%s/%s' % (config, build)) Attachment.delete_all(self.env, 'build', resource.id, db)
if "edit" not in mwsite.rights: raise Exception("%(mwiki_user)s does not have edit permissions on %(mwiki_host)s" % args) if "createpage" not in mwsite.rights: raise Exception("%(mwiki_user)s does not have page creation permissions on %(mwiki_host)s" % args) if args.sqlite_db is not None: import sqlite3 sqliteconn = sqlite3.connect(args.sqlite_db) traccur = sqliteconn.cursor() elif args.trac_path is not None: from trac.env import Environment tracenv = Environment(args.trac_path) tracdb = tracenv.get_db_cnx() traccur = tracdb.cursor() if args.prefix != "": args.prefix = "%s - " % args.prefix traccur.execute("SELECT `name`, `author`, `text`, `comment` FROM `wiki` ORDER BY `version` ASC") for page in traccur: # Format the page from Trac to MW format formatter = WikiFormatter(page[2]) newpage = {} newpage["name"] = "%s%s" % (args.prefix, page[0]) newpage["author"] = page[1] newpage["text"] = formatter.parse() newpage["comment"] = page[3]
class TracDatabase(object): def __init__(self, path, append): self.append = _append self.env = Environment(path) self._db = self.env.get_db_cnx() self._db.autocommit = False self.loginNameCache = {} self.fieldNameCache = {} def db(self): return self._db def hasTickets(self): c = self.db().cursor() c.execute('''SELECT count(*) FROM ticket''') return int(c.fetchall()[0][0]) > 0 def assertNoTickets(self): if not self._append or self.hasTickets(): raise Exception("Will not modify database with existing tickets!") return def setSeverityList(self, s): """Remove all severities, set them to `s`""" self.assertNoTickets() c = self.db().cursor() c.execute("""DELETE FROM enum WHERE type='severity'""") for value, i in s: print "inserting severity ", value, " ", i c.execute( """INSERT INTO enum (type, name, value) VALUES (%s, %s, %s)""", ( "severity", value.encode('utf-8'), i, )) self.db().commit() def setPriorityList(self, s): """Remove all priorities, set them to `s`""" self.assertNoTickets() c = self.db().cursor() c.execute("""DELETE FROM enum WHERE type='priority'""") for value, i in s: print "inserting priority ", value, " ", i c.execute( """INSERT INTO enum (type, name, value) VALUES (%s, %s, %s)""", ( "priority", value.encode('utf-8'), i, )) self.db().commit() def setComponentList(self, l, key): """Remove all components, set them to `l`""" self.assertNoTickets() c = self.db().cursor() c.execute("""DELETE FROM component""") for comp in l: print "inserting component '", comp[key], "', owner", comp['owner'] c.execute( """INSERT INTO component (name, owner) VALUES (%s, %s)""", ( comp[key].encode('utf-8'), comp['owner'].encode('utf-8'), )) self.db().commit() def setVersionList(self, v, key): """Remove all versions, set them to `v`""" self.assertNoTickets() c = self.db().cursor() c.execute("""DELETE FROM version""") for vers in v: print "inserting version ", vers[key] c.execute("""INSERT INTO version (name) VALUES (%s)""", (vers[key].encode('utf-8'), )) self.db().commit() def setMilestoneList(self, m, key): """Remove all milestones, set them to `m`""" self.assertNoTickets() c = self.db().cursor() c.execute("""DELETE FROM milestone""") for ms in m: print "inserting milestone ", ms[key] c.execute( """INSERT INTO milestone (name, due, completed) VALUES (%s, %s, %s)""", (ms[key].encode('utf-8'), self.convertTime( ms['date_order']), ms['released'])) self.db().commit() def addTicket(self, id, time, changetime, component, severity, priority, owner, reporter, cc, version, milestone, status, resolution, summary, description, keywords): c = self.db().cursor() if IGNORE_VERSION: version = '' desc = description type = 'defect' if component == 'Features' or severity == 'feature': type = 'enhancement' if PREFORMAT_COMMENTS: desc = '{{{\n%s\n}}}' % desc print "inserting ticket %s -- \"%s\"" % (id, summary[0:40].replace( "\n", " ")) c.execute( """INSERT INTO ticket (type, time, changetime, component, severity, priority, owner, reporter, cc, version, milestone, status, resolution, summary, description, keywords) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""", (type, self.convertTime(time), self.convertTime(changetime), component.encode('utf-8'), severity.encode('utf-8'), priority.encode('utf-8'), owner, reporter, cc, version, milestone.encode('utf-8'), status.lower(), resolution, summary.decode('utf-8'), desc, keywords.encode('utf-8'))) self.db().commit() ## TODO: add database-specific methods to get the last inserted ticket's id... ## PostgreSQL: # c.execute('''SELECT currval("ticket_id_seq")''') ## SQLite: # c.execute('''SELECT last_insert_rowid()''') ## MySQL: # c.execute('''SELECT LAST_INSERT_ID()''') # Oh, Trac db abstraction layer already has a function for this... return self.db().get_last_id(c, 'ticket') def convertTime(self, time2): time2 = datetime.fromtimestamp(time2) return long(str(int(time.mktime(time2.timetuple()))) + '000000') def addTicketComment(self, ticket, time, author, value): #return print " * adding comment \"%s...\"" % value[0:40] comment = value if PREFORMAT_COMMENTS: comment = '{{{\n%s\n}}}' % comment c = self.db().cursor() c.execute( """INSERT INTO ticket_change (ticket, time, author, field, oldvalue, newvalue) VALUES (%s, %s, %s, %s, %s, %s)""", (ticket, self.convertTime(time), author, 'comment', '', comment)) self.db().commit() def addTicketChange(self, ticket, time, author, field, oldvalue, newvalue): if (field[0:4] == 'doba'): return if field == 'milestone': field = 'product_version' print " * adding ticket change \"%s\": \"%s\" -> \"%s\" (%s)" % ( field, oldvalue[0:20], newvalue[0:20], time) c = self.db().cursor() #workaround 'unique' ticket_change warnings POTENTIALLY BAD IDEA ALERT sql = "SELECT * FROM ticket_change WHERE field='%s' AND ticket=%s AND time=%s" % ( field, ticket, self.convertTime(time)) c.execute(sql) fixtime = c.fetchall() if fixtime: time = time + 1 c.execute( """INSERT INTO ticket_change (ticket, time, author, field, oldvalue, newvalue) VALUES (%s, %s, %s, %s, %s, %s)""", (ticket, self.convertTime(time), author, field, oldvalue.encode('utf-8'), newvalue.encode('utf-8'))) self.db().commit() #workaround 'unique' ticket warnings POTENTIALLY BAD IDEA ALERT sql = "SELECT * FROM ticket WHERE %s='%s' AND id=%s AND time=%s" % ( field, newvalue, ticket, self.convertTime(time)) c.execute(sql) fixtime = c.fetchall() if fixtime: time = time + 1 # Now actually change the ticket because the ticket wont update itself! sql = "UPDATE ticket SET %s='%s' WHERE id=%s" % (field, newvalue, ticket) c.execute(sql) self.db().commit() # unused in 1.2 def addAttachment(self, id, attachment, description, author): print 'inserting attachment for ticket %s -- %s' % (id, description) attachment.filename = attachment.filename.encode('utf-8') self.env.create_attachment(self.db(), 'ticket', str(id), attachment, description.encode('utf-8'), author, 'unknown') def getLoginName(self, cursor, userid): if userid not in self.loginNameCache and userid is not None and userid != '': cursor.execute( "SELECT username,email,realname,last_visit FROM mantis_user_table WHERE id = %i" % int(userid)) result = cursor.fetchall() if result: loginName = result[0]['username'] print 'Adding user %s to sessions table' % loginName c = self.db().cursor() # check if user is already in the sessions table c.execute("SELECT sid FROM session WHERE sid = '%s'" % result[0]['username'].encode('utf-8')) r = c.fetchall() # if there was no user sid in the database already if not r: sessionSql = """INSERT INTO session (sid, authenticated, last_visit) VALUES (%s, %s, %d)""", ( result[0]['username'].encode('utf-8'), '1', self.convertTime(result[0]['last_visit'])) # pre-populate the session table and the realname/email table with user data try: c.execute(sessionSql) except: print 'failed executing sql: ' print sessionSql print 'could not insert %s into sessions table: sql error ' % ( loginName) self.db().commit() # insert the user's real name into session attribute table try: c.execute( """INSERT INTO session_attribute (sid, authenticated, name, value) VALUES (%s, %s, %s, %s)""", (result[0]['username'].encode('utf-8'), '1', 'name', result[0]['realname'].encode('utf-8'))) except: print 'failed executing session-attribute sql' self.db().commit() # insert the user's email into session attribute table try: c.execute( """INSERT INTO session_attribute (sid, authenticated, name, value) VALUES (%s, %s, %s, %s)""", (result[0]['username'].encode('utf-8'), '1', 'email', result[0]['email'].encode('utf-8'))) except: print 'failed executing session-attribute sql2' self.db().commit() else: print 'warning: unknown mantis userid %d, recording as anonymous' % userid loginName = '' self.loginNameCache[userid] = loginName elif userid is None or userid == '': self.loginNameCache[userid] = '' return self.loginNameCache[userid] def get_attachments_dir(self, bugid=0): if bugid > 0: return 'importfiles/%i/' % bugid else: return 'importfiles/' def _mkdir(newdir): """works the way a good mkdir should :) - already exists, silently complete - regular file in the way, raise an exception - parent directory(ies) does not exist, make them as well """ if os.path.isdir(newdir): pass elif os.path.isfile(newdir): raise OSError("a file with the same name as the desired " \ "dir, '%s', already exists." % newdir) else: head, tail = os.path.split(newdir) if head and not os.path.isdir(head): _mkdir(head) #print "_mkdir %s" % repr(newdir) if tail: os.mkdir(newdir)
def get_tracenv_userdata(self, req, path, userlist=''): """Retrieve account data from the environment at the specified path @param path path to the environment @param userlist comma separated list of users to restrict the result to (e.g. the users from the password file), each user enclosed in single quotes (for SQL) @return array (empty array if the environment uses a different password file than the master env calling us) """ self.env.log.debug('Get user data from %s' % (path, )) data = {} env = Environment(path) # if this environment uses a different password file, we return an empty dataset if self.env.config.get('account-manager', 'password_file') != env.config.get( 'account-manager', 'password_file'): self.env.log.info( 'Password files do not match, skipping environment %s' % (path, )) return data perm = PermissionSystem(env) if not 'TRAC_ADMIN' in perm.get_user_permissions(req.perm.username): raise PermissionError db = env.get_db_cnx() cursor = db.cursor() sync_fields = self.env.config.getlist('user_sync', 'sync_fields') attr = "'" + "','".join( sync_fields ) + "','email_verification_sent_to','email_verification_token'" self.env.log.debug('* Checking attributes: %s' % (attr, )) if userlist: cursor.execute( "SELECT sid,name,value FROM session_attribute WHERE sid IN (%s) AND name IN (%s)" % ( userlist, attr, )) else: cursor.execute( "SELECT sid,name,value FROM session_attribute WHERE name IN (%s)" % (attr, )) for row in cursor: if not row[0] in data: data[row[0]] = {} data[row[0]][row[1]] = row[2] for sid in data.iterkeys(): no_data = True for att in sync_fields: if att in data[sid]: no_data = False break if no_data: self.env.log.debug('No data for %s in %s' % ( sid, path, )) data[sid] = Null continue data[sid]['path'] = path cursor.execute( "SELECT authenticated FROM session_attribute WHERE sid='%s'" % (sid, )) for row in cursor: data[sid]['authenticated'] = row[0] cursor.execute( "SELECT datetime(last_visit,'unixepoch') AS last_visit FROM session WHERE sid='%s'" % (sid, )) for row in cursor: data[sid]['last_visit'] = row[0] return data
class TracDatabase(object): def __init__(self, path): self.env = Environment(path) self._db = self.env.get_db_cnx() self._db.autocommit = False self.loginNameCache = {} self.fieldNameCache = {} def db(self): return self._db def hasTickets(self): c = self.db().cursor() c.execute("SELECT count(*) FROM Ticket") return int(c.fetchall()[0][0]) > 0 def assertNoTickets(self): if self.hasTickets(): raise Exception("Will not modify database with existing tickets!") def setSeverityList(self, s): """Remove all severities, set them to `s`""" self.assertNoTickets() c = self.db().cursor() c.execute("DELETE FROM enum WHERE type='severity'") for value, i in s: print " inserting severity '%s' - '%s'" % (value, i) c.execute("""INSERT INTO enum (type, name, value) VALUES (%s, %s, %s)""", ("severity", value.encode('utf-8'), i)) self.db().commit() def setPriorityList(self, s): """Remove all priorities, set them to `s`""" self.assertNoTickets() c = self.db().cursor() c.execute("DELETE FROM enum WHERE type='priority'") for value, i in s: print " inserting priority '%s' - '%s'" % (value, i) c.execute("""INSERT INTO enum (type, name, value) VALUES (%s, %s, %s)""", ("priority", value.encode('utf-8'), i)) self.db().commit() def setComponentList(self, l, key): """Remove all components, set them to `l`""" self.assertNoTickets() c = self.db().cursor() c.execute("DELETE FROM component") for comp in l: print " inserting component '%s', owner '%s'" % \ (comp[key], comp['owner']) c.execute("INSERT INTO component (name, owner) VALUES (%s, %s)", (comp[key].encode('utf-8'), comp['owner'].encode('utf-8'))) self.db().commit() def setVersionList(self, v, key): """Remove all versions, set them to `v`""" self.assertNoTickets() c = self.db().cursor() c.execute("DELETE FROM version") for vers in v: print " inserting version '%s'" % (vers[key]) c.execute("INSERT INTO version (name) VALUES (%s)", (vers[key].encode('utf-8'),)) self.db().commit() def setMilestoneList(self, m, key): """Remove all milestones, set them to `m`""" self.assertNoTickets() c = self.db().cursor() c.execute("DELETE FROM milestone") for ms in m: milestone = ms[key] print " inserting milestone '%s'" % (milestone) c.execute("INSERT INTO milestone (name) VALUES (%s)", (milestone.encode('utf-8'),)) self.db().commit() def addTicket(self, id, time, changetime, component, severity, priority, owner, reporter, cc, version, milestone, status, resolution, summary, description, keywords): c = self.db().cursor() desc = description.encode('utf-8') type = "defect" if severity.lower() == "enhancement": severity = "minor" type = "enhancement" if PREFORMAT_COMMENTS: desc = '{{{\n%s\n}}}' % desc if REPLACE_BUG_NO: if BUG_NO_RE.search(desc): desc = re.sub(BUG_NO_RE, BUG_NO_REPL, desc) if PRIORITIES_MAP.has_key(priority): priority = PRIORITIES_MAP[priority] print " inserting ticket %s -- %s" % (id, summary) c.execute("""INSERT INTO ticket (id, type, time, changetime, component, severity, priority, owner, reporter, cc, version, milestone, status, resolution, summary, description, keywords) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""", (id, type.encode('utf-8'), time.strftime('%s'), changetime.strftime('%s'), component.encode('utf-8'), severity.encode('utf-8'), priority.encode('utf-8'), owner, reporter, cc, version, milestone.encode('utf-8'), status.lower(), resolution, summary.encode('utf-8'), desc, keywords)) self.db().commit() return self.db().get_last_id(c, 'ticket') def addTicketComment(self, ticket, time, author, value): comment = value.encode('utf-8') if PREFORMAT_COMMENTS: comment = '{{{\n%s\n}}}' % comment if REPLACE_BUG_NO: if BUG_NO_RE.search(comment): comment = re.sub(BUG_NO_RE, BUG_NO_REPL, comment) c = self.db().cursor() c.execute("""INSERT INTO ticket_change (ticket, time, author, field, oldvalue, newvalue) VALUES (%s, %s, %s, %s, %s, %s)""", (ticket, time.strftime('%s'), author, 'comment', '', comment)) self.db().commit() def addTicketChange(self, ticket, time, author, field, oldvalue, newvalue): c = self.db().cursor() if field == "owner": if LOGIN_MAP.has_key(oldvalue): oldvalue = LOGIN_MAP[oldvalue] if LOGIN_MAP.has_key(newvalue): newvalue = LOGIN_MAP[newvalue] if field == "priority": if PRIORITIES_MAP.has_key(oldvalue.lower()): oldvalue = PRIORITIES_MAP[oldvalue.lower()] if PRIORITIES_MAP.has_key(newvalue.lower()): newvalue = PRIORITIES_MAP[newvalue.lower()] # Doesn't make sense if we go from highest -> highest, for example. if oldvalue == newvalue: return c.execute("""INSERT INTO ticket_change (ticket, time, author, field, oldvalue, newvalue) VALUES (%s, %s, %s, %s, %s, %s)""", (ticket, time.strftime('%s'), author, field, oldvalue.encode('utf-8'), newvalue.encode('utf-8'))) self.db().commit() def addAttachment(self, author, a): description = a['description'].encode('utf-8') id = a['bug_id'] filename = a['filename'].encode('utf-8') filedata = StringIO.StringIO(a['thedata'].tostring()) filesize = len(filedata.getvalue()) time = a['creation_ts'] print " ->inserting attachment '%s' for ticket %s -- %s" % \ (filename, id, description) attachment = Attachment(self.env, 'ticket', id) attachment.author = author attachment.description = description attachment.insert(filename, filedata, filesize, time.strftime('%s')) del attachment def getLoginName(self, cursor, userid): if userid not in self.loginNameCache: cursor.execute("SELECT * FROM profiles WHERE userid = %s", (userid)) loginName = cursor.fetchall() if loginName: loginName = loginName[0]['login_name'] else: print """WARNING: unknown bugzilla userid %d, recording as anonymous""" % (userid) loginName = "anonymous" loginName = LOGIN_MAP.get(loginName, loginName) self.loginNameCache[userid] = loginName return self.loginNameCache[userid] def getFieldName(self, cursor, fieldid): if fieldid not in self.fieldNameCache: cursor.execute("SELECT * FROM fielddefs WHERE fieldid = %s", (fieldid)) fieldName = cursor.fetchall() if fieldName: fieldName = fieldName[0]['name'].lower() else: print "WARNING: unknown bugzilla fieldid %d, \ recording as unknown" % (userid) fieldName = "unknown" self.fieldNameCache[fieldid] = fieldName return self.fieldNameCache[fieldid]
class Client(object): def __init__(self, env_path): self.env_path = env_path self.env = Environment(env_path) self.db_cnx = self.env.get_db_cnx() self._registered_users_logins = [] self._timetracking_plugins = self._get_timetracking_plugins() def _get_timetracking_plugins(self): plugins = {} if tracLib.SUPPORT_TIME_TRACKING == 'auto': for plugin in tracLib.timetracking.plugins: plugin_name = plugin.get_name() for com_name, com_enabled in self.env._component_rules.items(): if com_name.startswith(plugin_name) and com_enabled and plugin_name not in plugins: plugins[plugin_name] = plugin(self.env) else: for plugin in tracLib.timetracking.plugins: plugin_name = plugin.get_name() if plugin_name == tracLib.SUPPORT_TIME_TRACKING: plugins[plugin_name] = plugin(self.env) break; for plugin_name in plugins.keys(): print "Plugin '%s' will be used to get workitems." % plugin_name return plugins.values() def get_project_description(self): return self.env.project_description def get_users(self): result = self.env.get_known_users() trac_users = list([]) for user in result: user_login = user[0].lower() if user_login in self._registered_users_logins: continue u = TracUser(user_login) u.email = user[2] trac_users.append(u) self._registered_users_logins.append(user_login) # if we accept only authorised users, we don't have any more users to return # all of them were returned by "get_known_users" method if not tracLib.ACCEPT_NON_AUTHORISED_USERS: return trac_users # here we must to get component owners, issue reporters, owners and attachment authors # that are not registered users user_fields = [("owner", "component"), ("reporter", "ticket"), ("owner", "ticket"), ("author", "attachment")] first = True request = "" for column_name, table_name in user_fields : if first: first = False else: request += "UNION " request += "SELECT DISTINCT lower(%s) FROM %s " % (column_name, table_name) cursor = self.db_cnx.cursor() cursor.execute(request) for row in cursor: if row[0] not in self._registered_users_logins: trac_user = self._get_non_authorised_user(row[0]) if trac_user is not None : trac_users.append(trac_user) self._registered_users_logins.append(trac_user.name) return trac_users def _get_non_authorised_user(self, user_name): if user_name is None : return None # non authorized users in trac are stored like this "name <email_address>" start = user_name.find("<") end = user_name.rfind(">") # we don't accept users who didn't leave the email if (start > -1) and (end > start + 1): if user_name.find("@", start, end) > 0: user = TracUser(user_name[start + 1 : end].replace(" ", "_")) user.email = user_name[start + 1 : end].replace(" ", "_") return user return None def _get_user_login(self, user_name): if user_name is None: return None if user_name in self._registered_users_logins: return user_name if not tracLib.ACCEPT_NON_AUTHORISED_USERS: return None user = self._get_non_authorised_user(user_name) if (user is None) or (user.name not in self._registered_users_logins) : return None return user.name def get_severities(self): return self._get_data_from_enum("severity") def get_issue_types(self): return self._get_data_from_enum("ticket_type") def get_issue_priorities(self): return self._get_data_from_enum("priority") def get_issue_resolutions(self): return [TracResolution(name) for name in self._get_data_from_enum("resolution")] def get_components(self): cursor = self.db_cnx.cursor() cursor.execute("SELECT name, owner, description FROM component") trac_components = list([]) for row in cursor: component = TracComponent(row[0]) component.owner = self._get_user_login(component.owner) if row[2] is not None: component.description = row[2] trac_components.append(component) return trac_components def get_versions(self): cursor = self.db_cnx.cursor() cursor.execute("SELECT name, time, description FROM version") trac_versions = list([]) for row in cursor: version = TracVersion(row[0]) if row[1]: version.time = to_unix_time(row[1]) if row[2] is not None: version.description = row[2] trac_versions.append(version) return trac_versions def get_issues(self): cursor = self.db_cnx.cursor() cursor.execute("SELECT id, type, time, changetime, component, severity, priority, owner, reporter," "cc, version, status, resolution, summary, description, keywords FROM ticket") trac_issues = list([]) for row in cursor: issue = TracIssue(row[0]) issue.time = to_unix_time(row[2]) issue.changetime = to_unix_time(row[3]) issue.reporter = self._get_user_login(row[8]) if row[9] is not None: cc = row[9].split(",") for c in cc: if len(c) > 0: cc_name = self._get_user_login(c.strip()) if cc_name is not None: issue.cc.add(cc_name) issue.summary = row[13] issue.description = row[14] issue.custom_fields["Type"] = row[1] issue.custom_fields["Component"] = row[4] issue.custom_fields["Severity"] = row[5] issue.custom_fields["Priority"] = row[6] issue.custom_fields["Owner"] = self._get_user_login(row[7]) issue.custom_fields["Version"] = row[10] issue.custom_fields["Status"] = row[11] issue.custom_fields["Resolution"] = row[12] if row[15] is not None: keywords = row[15].rsplit(",") for kw in keywords: if len(kw) > 0: issue.keywords.add(kw.strip()) #getting custom fields from ticket_custom table custom_field_cursor = self.db_cnx.cursor() custom_field_cursor.execute("SELECT name, value FROM ticket_custom WHERE ticket=%s", (str(row[0]),)) for cf in custom_field_cursor: issue.custom_fields[cf[0].capitalize()] = cf[1] # getting attachments from attachment table attachment_cursor = self.db_cnx.cursor() attachment_cursor.execute("SELECT filename, size, time, description, author FROM attachment WHERE " "type = %s AND id = %s", ("ticket", str(issue.id))) #path = self.env_path + "/attachments/ticket/" + str(issue.id) + "/" for elem in attachment_cursor: #at = TracAttachment(path + elem[0]) at = TracAttachment(Attachment._get_path(self.env.path, 'ticket', str(issue.id), elem[0])) at.name = elem[0] at.size = elem[1] at.time = to_unix_time(elem[2]) at.description = elem[3] at.author_name = elem[4] issue.attachment.add(at) trac_issues.append(issue) #getting comments change_cursor = self.db_cnx.cursor() change_cursor.execute("SELECT time, author, newvalue, oldvalue FROM ticket_change WHERE ticket = %s AND field = %s ORDER BY time DESC", (str(row[0]), "comment",)) for elem in change_cursor: if (elem[2] is None) or (not len(elem[2].lstrip())): continue comment = TracComment(to_unix_time(elem[0])) comment.author = str(elem[1]) comment.content = unicode(elem[2]) comment.id = elem[3] issue.comments.add(comment) #getting workitems for ttp in self._timetracking_plugins: issue.workitems.update(set(ttp[row[0]])) return trac_issues def get_custom_fields_declared(self): ini_file_path = self.env_path + "/conf/trac.ini" parser = ConfigParser() parser.read(ini_file_path) if not("ticket-custom" in parser.sections()): return set([]) result = parser.items("ticket-custom") items = dict([]) for elem in result: items[elem[0]] = elem[1] keys = items.keys() custom_fields = list([]) for k in keys: if not("." in k): field = TracCustomFieldDeclaration(k.capitalize()) field.type = items[k] options_key = k + ".options" if options_key in items: opts_str = items[options_key] opts = opts_str.rsplit("|") for o in opts: field.options.append(o) value_key = k + ".value" if value_key in items: field.value = items[value_key] label_key = k + ".label" if label_key in items: field.label = items[label_key] custom_fields.append(field) return custom_fields def _get_data_from_enum(self, type_name): cursor = self.db_cnx.cursor() cursor.execute("SELECT name, value FROM enum WHERE type=%s", (type_name,)) return [row[0] for row in cursor]
def delete_watchlist_tables(envpath, tables=('watchlist', 'watchlist_settings', 'system'), user=None): """Deletes all watchlist DB entries => Uninstaller""" from trac.env import Environment try: env = Environment(envpath) except: print "Given path '%s' seems not to be a Trac environment." % envpath sys.exit(3) db = env.get_db_cnx() if user is not None: cursor = db.cursor() if 'watchlist' in tables: try: cursor.execute("DELETE FROM watchlist WHERE wluser=%s", (user, )) print "Deleted user entries from 'watchlist' table." except Exception as e: db.rollback() print "Could not delete user entry from 'watchlist' table: "\ + unicode(e) cursor = db.cursor() if 'watchlist_settings' in tables: try: cursor.execute( "DELETE FROM watchlist_settings WHERE wluser=%s", (user, )) print "Deleted user entries from 'watchlist_settings' table." except Exception as e: db.rollback() print "Could not delete user entry from 'watchlist_settings' table: "\ + unicode(e) db.commit() print "Finished." return if 'watchlist' in tables: cursor = db.cursor() try: cursor.execute("DROP TABLE watchlist") print "Deleted 'watchlist' table." except: db.rollback() print "No 'watchlist' table for deletion found." if 'watchlist_settings' in tables: cursor = db.cursor() try: cursor.execute("DROP TABLE watchlist_settings") print "Deleted 'watchlist_settings' table." except: db.rollback() print "No 'watchlist_settings' table for deletion found." if 'system' in tables: cursor = db.cursor() try: cursor.execute("DELETE FROM system WHERE name='watchlist_version'") print "Deleted watchlist version entry from system table." except Exception as e: db.rollback() print "Could not delete 'watchlist_version' from 'system' table: "\ + unicode(e) db.commit() print "Finished."
raise Exception( "%(mwiki_user)s does not have edit permissions on %(mwiki_host)s" % args) if 'createpage' not in mwsite.rights: raise Exception( "%(mwiki_user)s does not have page creation permissions on %(mwiki_host)s" % args) if args.sqlite_db is not None: import sqlite3 sqliteconn = sqlite3.connect(args.sqlite_db) traccur = sqliteconn.cursor() elif args.trac_path is not None: from trac.env import Environment tracenv = Environment(args.trac_path) tracdb = tracenv.get_db_cnx() traccur = tracdb.cursor() if args.prefix != "": args.prefix = "%s - " % args.prefix traccur.execute( "SELECT `name`, `author`, `text`, `comment` FROM `wiki` ORDER BY `version` ASC" ) for page in traccur: #Format the page from Trac to MW format formatter = WikiFormatter(page[2]) newpage = {} newpage['name'] = "%s%s" % (args.prefix, page[0]) newpage['author'] = page[1]
class Trac(object): def __init__(self, path): '''Basic object that supports the wiki and all that jazz''' self._env = Environment(os.path.abspath(path)) purl = self._env.project_url if purl.endswith('/'): purl = purl[:-1] if purl: self.name = purl.split('/')[-1] else: self.name = self._env.project_name def listWikiPages(self): '''Return a list of all wiki pages that were not written by the 'trac' user''' db = self._env.get_db_cnx() cursor = db.cursor() wikiPagesQuery = "select distinct name from wiki where author != 'trac'" res = cursor.execute(wikiPagesQuery) pages = res.fetchall() names = [x[0] for x in pages] return names def listTickets(self): '''Return a list of all ticket numbers''' db = self._env.get_db_cnx() cursor = db.cursor() ticketsQuery = 'select distinct id from ticket' res = cursor.execute(ticketsQuery) ticketsRes = res.fetchall() tickets = [x[0] for x in ticketsRes] return tickets def maxTicket(self): '''Return the largest ticket number''' db = self._env.get_db_cnx() cursor = db.cursor() maxTicketQuery = 'select max(id) from ticket' res = cursor.execute(maxTicketQuery) (maxTicket, ) = res.fetchone() return maxTicket def listVersions(self): '''List all the versions''' db = self._env.get_db_cnx() cursor = db.cursor() versionsQuery = "select name from version" res = cursor.execute(versionsQuery) versions = [x[0] for x in res.fetchall()] return versions def listComponents(self): '''List all the ticket components''' db = self._env.get_db_cnx() cursor = db.cursor() componentsQuery = "select name from component" res = cursor.execute(componentsQuery) components = [x[0] for x in res.fetchall()] return components def listEnums(self): '''List all the enums''' db = self._env.get_db_cnx() cursor = db.cursor() enumsQuery = "select name, type from enum" res = cursor.execute(enumsQuery) return res.fetchall() def listMilestones(self): '''List all the milestones''' db = self._env.get_db_cnx() cursor = db.cursor() milestonesQuery = "select name from milestone" res = cursor.execute(milestonesQuery) milestones = [x[0] for x in res.fetchall()] return milestones def getAllInfo(self): all = {} all['wikiNames'] = self.listWikiPages() all['maxTicket'] = self.maxTicket() all['versions'] = self.listVersions() all['components'] = self.listComponents() all['enums'] = self.listEnums() all['milestones'] = self.listMilestones() return all def getWikiPageAll(self, page): '''Get all the versions of a wiki page as a list of dicts and a list of attachments''' db = self._env.get_db_cnx() cursor = db.cursor() pageCountRes = cursor.execute('select count(*) as count from wiki where name = %s', (page,)) pageCount = pageCountRes.fetchone()[0] assert pageCount >= 1, 'Page %s not found in %s' % (page, self.name) attachments = [] pageAttachmentQuery = "select type, id, filename, size, time, description, author, ipnr from attachment where type = 'wiki' and id = %s" pageAttachmentRes = cursor.execute(pageAttachmentQuery, (page,)) for attachment in pageAttachmentRes: thisAttachment = dict(zip([d[0] for d in pageAttachmentRes.description], attachment)) thisAttachment['fileobj'] = Attachment(self._env, 'wiki', page, thisAttachment['filename']).open() attachments.append(thisAttachment) baseQuery = 'select name, version, time, author, ipnr, text, comment, readonly from wiki where name = %s' res = cursor.execute(baseQuery, (page,)) wikiData = [] for row in res: wikiData.append(dict(zip([d[0] for d in res.description], row))) return wikiData, attachments def getWikiPageCurrent(self, page): '''Get the current version of a wiki page as a dict''' db = self._env.get_db_cnx() cursor = db.cursor() pageCountRes = cursor.execute('select count(*) as count from wiki where name = %s', (page,)) pageCount = pageCountRes.fetchone()[0] assert pageCount >= 1, 'Page %s not found in %s' % (page, self.name) pageQuery = 'select name, version, time, author, ipnr, text, comment, readonly from wiki where name = %s and version = (select max(version) from wiki where name = %s)' pageRes = cursor.execute(pageQuery, (page,page)) wikiPage = dict(zip([d[0] for d in pageRes.description], pageRes.fetchone())) wikiPage['attachment'] = [] pageAttachmentQuery = "select type, id, filename, size, time, description, author, ipnr from attachment where type = 'wiki' and id = %s" pageAttachmentRes = cursor.execute(pageAttachmentQuery, (page,)) for attachment in pageAttachmentRes: thisAttachment = dict(zip([d[0] for d in pageAttachmentRes.description], attachment)) thisAttachment['fileobj'] = Attachment(self._env, 'wiki', page, thisAttachment['filename']).open() wikiPage['attachment'].append(thisAttachment) return wikiPage def addWikiPage(self, page, attachments): '''Add a wiki page as a list of dictionaries''' db = self._env.get_db_cnx() cursor = db.cursor() pageCountRes = cursor.execute('select count(*) as count from wiki where name = %s', (page[0]['name'],)) pageCount = pageCountRes.fetchone()[0] assert pageCount == 0, 'Page %s found in %s' % (page[0]['name'], self.name) insertWikiQuery = 'insert into wiki (name, version, time, author, ipnr, text, comment, readonly) values (%s, %s, %s, %s, %s, %s, %s, %s)' for pV in page: insertValues = (pV['name'], pV['version'], pV['time'], pV['author'], pV['ipnr'], pV['text'], pV['comment'], pV['readonly']) insertRes = cursor.execute(insertWikiQuery, insertValues) for a in attachments: pageAttach = Attachment(self._env, 'wiki', pV['name']) pageAttach.description = a['description'] pageAttach.author = a['author'] pageAttach.ipnr = a['ipnr'] pageAttach.insert(a['filename'], a['fileobj'], a['size'], t=a['time']) db.commit() def getTicket(self, id): '''Get a ticket id as a dict''' db = self._env.get_db_cnx() cursor = db.cursor() idCountRes = cursor.execute('select count(*) as count from ticket where id = %s', (id,)) idCount = idCountRes.fetchone()[0] assert idCount >= 1, 'Page %s not found in %s' % (id, self.id) mainTicketQuery = 'select id, type, time, changetime, component, severity, priority, owner, \ reporter, cc, version, milestone, status, resolution, summary, description, keywords from ticket where id = %s' mainTicketRes = cursor.execute(mainTicketQuery, (id, )) ticket = dict(zip([d[0] for d in mainTicketRes.description], mainTicketRes.fetchone())) ticket['ticket_change'] = [] ticketChangeQuery = 'select time, author, field, oldvalue, newvalue from ticket_change where ticket = %s' ticketChangeRes = cursor.execute(ticketChangeQuery, (id, )) for ticket_change in ticketChangeRes: ticket['ticket_change'].append(dict(zip([d[0] for d in ticketChangeRes.description], ticket_change))) ticket['attachment'] = [] ticketAttachmentQuery = 'select type, id, filename, size, time, description, author, ipnr from attachment where type = \'ticket\' and id = %s' ticketAttachmentRes = cursor.execute(ticketAttachmentQuery, (id, )) for attachment in ticketAttachmentRes: thisAttachment = dict(zip([d[0] for d in ticketAttachmentRes.description], attachment)) thisAttachment['fileobj'] = Attachment(self._env, 'ticket', id, thisAttachment['filename']).open() ticket['attachment'].append(thisAttachment) return ticket def addTicket(self, ticket, source): '''Add a ticket from a dict''' db = self._env.get_db_cnx() cursor = db.cursor() idCountRes = cursor.execute('select count(*) as count from ticket where id = %s', (ticket['id'],)) idCount = idCountRes.fetchone()[0] assert idCount == 0, 'Ticket %s found in %s' % (ticket['id'], self.name) insertMainTicketQuery = 'insert into ticket (id, type, time, changetime, component, severity, priority, owner, \ reporter, cc, version, milestone, status, resolution, summary, description, keywords) \ values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)' insertMainTicketValues = (ticket['id'], ticket['type'], ticket['time'], ticket['changetime'], ticket['component'], \ ticket['severity'], ticket['priority'], ticket['owner'], ticket['reporter'], ticket['cc'], ticket['version'], \ ticket['milestone'], ticket['status'], ticket['resolution'], ticket['summary'], ticket['description'], ticket['keywords']) insertMainTicketRes = cursor.execute(insertMainTicketQuery, insertMainTicketValues) #so we know where the ticket came from insertTicketSourceQuery = 'insert into ticket_custom (ticket, name, value) values (%s, %s, %s)' insertTicketSourceValues = (ticket['id'], 'project', source) insertTicketSourceRes = cursor.execute(insertTicketSourceQuery, insertTicketSourceValues) insertTicketChangeQuery = 'insert into ticket_change (ticket, time, author, field, oldvalue, newvalue) values (%s, %s, %s, %s, %s, %s)' for ticket_change in ticket['ticket_change']: insertTicketChangeValues = (ticket['id'], ticket_change['time'], ticket_change['author'], ticket_change['field'], ticket_change['oldvalue'], ticket_change['newvalue']) insertTicketChangeRes = cursor.execute(insertTicketChangeQuery, insertTicketChangeValues) for a in ticket['attachment']: ticketAttach = Attachment(self._env, 'ticket', ticket['id']) ticketAttach.description = a['description'] ticketAttach.author = a['author'] ticketAttach.ipnr = a['ipnr'] ticketAttach.insert(a['filename'], a['fileobj'], a['size'], t=a['time']) db.commit() def getComponent(self, comp): '''Get a component as a dict''' db = self._env.get_db_cnx() cursor = db.cursor() compCountRes = cursor.execute('select count(*) as count from component where name = %s', (comp,)) compCount = compCountRes.fetchone()[0] assert compCount >= 1, 'Component %s not found in %s' % (comp, self.name) baseQuery = 'select name, owner, description from component where name = %s' res = cursor.execute(baseQuery, (comp,)) return(dict(zip([d[0] for d in res.description], res.fetchone()))) def addComponent(self, comp): '''Add a component from a dict''' db = self._env.get_db_cnx() cursor = db.cursor() assert comp['name'] != '', 'No name given' compCountRes = cursor.execute('select count(*) as count from component where name = %s', (comp['name'],)) compCount = compCountRes.fetchone()[0] if compCount > 0: 'Component %s found in %s. Skipping the re-insertion.' % (comp['name'], self.name) else: insertComponentQuery = 'insert into component (name, owner, description) values (%s, %s, %s)' insertComponentValues = (comp['name'], comp['owner'], comp['description']) res = cursor.execute(insertComponentQuery, insertComponentValues) db.commit() def getMilestone(self, mile): '''Get a milestone as a dict''' db = self._env.get_db_cnx() cursor = db.cursor() mileCountRes = cursor.execute('select count(*) as count from milestone where name = %s', (mile,)) mileCount = mileCountRes.fetchone()[0] assert mileCount >= 1, 'Milestone %s not found in %s' % (mile, self.name) baseQuery = 'select name, due, completed, description from milestone where name = %s' res = cursor.execute(baseQuery, (mile,)) return(dict(zip([d[0] for d in res.description], res.fetchone()))) def addMilestone(self, mile): '''Add a milestone from a dict''' db = self._env.get_db_cnx() cursor = db.cursor() assert mile['name'] != '', 'No name given' mileCountRes = cursor.execute('select count(*) as count from milestone where name = %s', (mile['name'],)) mileCount = mileCountRes.fetchone()[0] if mileCount > 0: 'Milestone %s found in %s. Skipping the re-insertion.' % (mile['name'], self.name) else: insertMilestoneQuery = 'insert into milestone (name, due, completed, description) values (%s, %s, %s, %s)' insertMilestoneValues = (mile['name'], mile['due'], mile['completed'], mile['description']) res = cursor.execute(insertMilestoneQuery, insertMilestoneValues) db.commit() def getEnum(self, enum): '''Get an enum as a dict. Enum should be a tupe of (name, type)''' db = self._env.get_db_cnx() cursor = db.cursor() enumCountRes = cursor.execute('select count(*) as count from enum where name = %s and type = %s', enum) enumCount = enumCountRes.fetchone()[0] assert enumCount >= 1, 'Enum %s not found in %s' % (enum, self.name) baseQuery = 'select name, type, value from enum where name = %s and type = %s' res = cursor.execute(baseQuery, enum) return(dict(zip([d[0] for d in res.description], res.fetchone()))) def addEnum(self, enum): '''Add a enum from a dict''' db = self._env.get_db_cnx() cursor = db.cursor() assert enum['name'] != '', 'No name given' enumCountRes = cursor.execute('select count(*) as count from enum where name = %s and type = %s', (enum['name'], enum['type'])) enumCount = enumCountRes.fetchone()[0] if enumCount > 0: print 'Enum %s found in %s. Skipping the re-insertion.' % (enum['name'], self.name) else: insertEnumQuery = 'insert into enum (name, type, value) values (%s, %s, %s)' insertEnumValues = (enum['name'], enum['type'], enum['value']) res = cursor.execute(insertEnumQuery, insertEnumValues) db.commit() def getVersion(self, version): '''Get a version as a dict''' db = self._env.get_db_cnx() cursor = db.cursor() versionCountRes = cursor.execute('select count(*) as count from version where name = %s', (version,)) versionCount = versionCountRes.fetchone()[0] assert versionCount >= 1, 'Version %s not found in %s' % (version, self.name) baseQuery = 'select name, time, description from version where name = %s' res = cursor.execute(baseQuery, (version,)) return(dict(zip([d[0] for d in res.description], res.fetchone()))) def addVersion(self, version): '''Add a version from a dict''' db = self._env.get_db_cnx() cursor = db.cursor() assert version['name'] != '', 'No name given' versionCountRes = cursor.execute('select count(*) as count from version where name = %', (version['name'],)) versionCount = versionCountRes.fetchone()[0] if versionCount > 0: print 'Version %s found in %s. Skipping the re-insertion.' % (version['name'], self.name) else: insertVersionQuery = 'insert into version (name, time, description) values (%s, %s, %s)' insertVersionValues = (version['name'], version['time'], version['description']) res = cursor.execute(insertVersionQuery, insertVersionValues) db.commit() def getRepository(self): '''Get the repository info, particularly the path and type''' repository = {} repository['type'] = self._env.config.get('trac', 'repository_type') repository['dir'] = self._env.config.get('trac', 'repository_dir') return repository def addRepository(self, repository): '''Add a repository from a dict specifying name, type and dir. This adds using the multiple repository functionality.''' assert repository.has_key('name') and repository.has_key('type') and repository.has_key('dir'), "Repository info not specified" self._env.config.set('repositories', '%s.dir' % repository['name'], repository['dir']) if repository['type'] == 'svn': repotype = 'direct-svnfs' else: repotype = repository['type'] self._env.config.set('repositories', '%s.type' % repository['name'], repotype) self._env.config.save()
class TracDatabase(object): def __init__(self, path): self.env = Environment(path) self._db = self.env.get_db_cnx() self._db.autocommit = False self.loginNameCache = {} self.fieldNameCache = {} def db(self): return self._db def hasTickets(self): c = self.db().cursor() c.execute('''SELECT count(*) FROM ticket''') return int(c.fetchall()[0][0]) > 0 def assertNoTickets(self): if self.hasTickets(): raise Exception("Will not modify database with existing tickets!") def setSeverityList(self, s): """Remove all severities, set them to `s`""" self.assertNoTickets() c = self.db().cursor() c.execute("""DELETE FROM enum WHERE type='severity'""") for value, i in s: print "inserting severity ", value, " ", i c.execute("""INSERT INTO enum (type, name, value) VALUES (%s, %s, %s)""", ("severity", value.encode('utf-8'), i,)) self.db().commit() def setPriorityList(self, s): """Remove all priorities, set them to `s`""" self.assertNoTickets() c = self.db().cursor() c.execute("""DELETE FROM enum WHERE type='priority'""") for value, i in s: print "inserting priority ", value, " ", i c.execute("""INSERT INTO enum (type, name, value) VALUES (%s, %s, %s)""", ("priority", value.encode('utf-8'), i,)) self.db().commit() def setComponentList(self, l, key): """Remove all components, set them to `l`""" self.assertNoTickets() c = self.db().cursor() c.execute("""DELETE FROM component""") for comp in l: print "inserting component '",comp[key],"', owner", comp['owner'] c.execute("""INSERT INTO component (name, owner) VALUES (%s, %s)""", (comp[key].encode('utf-8'), comp['owner'].encode('utf-8'),)) self.db().commit() def setVersionList(self, v, key): """Remove all versions, set them to `v`""" self.assertNoTickets() c = self.db().cursor() c.execute("""DELETE FROM version""") for vers in v: print "inserting version ", vers[key] c.execute("""INSERT INTO version (name) VALUES (%s)""", (vers[key].encode('utf-8'),)) self.db().commit() def setMilestoneList(self, m, key): """Remove all milestones, set them to `m`""" self.assertNoTickets() c = self.db().cursor() c.execute("""DELETE FROM milestone""") for ms in m: print "inserting milestone ", ms[key] c.execute("""INSERT INTO milestone (name, due, completed) VALUES (%s, %s, %s)""", (ms[key].encode('utf-8'), self.convertTime(ms['date_order']), ms['released'])) self.db().commit() def addTicket(self, id, time, changetime, component, severity, priority, owner, reporter, cc, version, milestone, status, resolution, summary, description, keywords): c = self.db().cursor() if IGNORE_VERSION: version='' desc = description type = 'defect' if component == 'Features' or severity == 'feature': type = 'enhancement' if PREFORMAT_COMMENTS: desc = '{{{\n%s\n}}}' % desc print "inserting ticket %s -- \"%s\"" % (id, summary[0:40].replace("\n", " ")) c.execute("""INSERT OR REPLACE INTO ticket (id, type, time, changetime, component, severity, priority, owner, reporter, cc, version, milestone, status, resolution, summary, description, keywords) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""", (id, type, self.convertTime(time), self.convertTime(changetime), component.encode('utf-8'), severity.encode('utf-8'), priority.encode('utf-8'), owner, reporter, cc, version, milestone.encode('utf-8'), status.lower(), resolution, summary.decode('utf-8'), desc, keywords.encode('utf-8'))) self.db().commit() ## TODO: add database-specific methods to get the last inserted ticket's id... ## PostgreSQL: # c.execute('''SELECT currval("ticket_id_seq")''') ## SQLite: # c.execute('''SELECT last_insert_rowid()''') ## MySQL: # c.execute('''SELECT LAST_INSERT_ID()''') # Oh, Trac db abstraction layer already has a function for this... return self.db().get_last_id(c,'ticket') def convertTime(self,time2): time2 = datetime.fromtimestamp(time2) return long(str(int(time.mktime(time2.timetuple()))) + '000000') def addTicketComment(self, ticket, time, author, value): #return print " * adding comment \"%s...\"" % value[0:40] comment = value if PREFORMAT_COMMENTS: comment = '{{{\n%s\n}}}' % comment c = self.db().cursor() c.execute("""INSERT OR IGNORE INTO ticket_change (ticket, time, author, field, oldvalue, newvalue) VALUES (%s, %s, %s, %s, %s, %s)""", (ticket, self.convertTime(time), author, 'comment', '', comment)) self.db().commit() def addTicketChange(self, ticket, time, author, field, oldvalue, newvalue): if (field[0:4]=='doba'): return if field == 'milestone': field = 'product_version' print " * adding ticket change \"%s\": \"%s\" -> \"%s\" (%s)" % (field, oldvalue[0:20], newvalue[0:20], time) c = self.db().cursor() #workaround 'unique' ticket_change warnings POTENTIALLY BAD IDEA ALERT sql = "SELECT * FROM ticket_change WHERE field='%s' AND ticket=%s AND time=%s" % (field, ticket, self.convertTime(time)) c.execute(sql) fixtime = c.fetchall() if fixtime: time = time + 1 c.execute("""INSERT OR IGNORE INTO ticket_change (ticket, time, author, field, oldvalue, newvalue) VALUES (%s, %s, %s, %s, %s, %s)""", (ticket, self.convertTime(time), author, field, oldvalue.encode('utf-8'), newvalue.encode('utf-8'))) self.db().commit() #workaround 'unique' ticket warnings POTENTIALLY BAD IDEA ALERT sql = "SELECT * FROM ticket WHERE %s='%s' AND id=%s AND time=%s" % (field, newvalue, ticket, self.convertTime(time)) c.execute(sql) fixtime = c.fetchall() if fixtime: time = time + 1 # Now actually change the ticket because the ticket wont update itself! sql = "UPDATE ticket SET %s='%s' WHERE id=%s" % (field, newvalue, ticket) c.execute(sql) self.db().commit() # unused in 1.2 def addAttachment(self, id, attachment, description, author): print 'inserting attachment for ticket %s -- %s' % (id, description) attachment.filename = attachment.filename.encode('utf-8') self.env.create_attachment(self.db(), 'ticket', str(id), attachment, description.encode('utf-8'), author, 'unknown') def getLoginName(self, cursor, userid): if userid not in self.loginNameCache and userid is not None and userid != '': cursor.execute("SELECT username,email,realname,last_visit FROM mantis_user_table WHERE id = %i" % int(userid)) result = cursor.fetchall() if result: loginName = result[0]['username'] print 'Adding user %s to sessions table' % loginName c = self.db().cursor() # check if user is already in the sessions table c.execute("SELECT sid FROM session WHERE sid = '%s'" % result[0]['username'].encode('utf-8')) r = c.fetchall() # if there was no user sid in the database already if not r: sessionSql = """INSERT INTO session (sid, authenticated, last_visit) VALUES (%s, %s, %s)""", (result[0]['username'].encode('utf-8'), '1', self.convertTime(result[0]['last_visit'])) # pre-populate the session table and the realname/email table with user data try: c.execute(sessionSql) except: print 'failed executing sql: ' print sessionSql print 'could not insert %s into sessions table: sql error ' % (loginName) self.db().commit() # insert the user's real name into session attribute table try: c.execute( """INSERT INTO session_attribute (sid, authenticated, name, value) VALUES (%s, %s, %s, %s)""", (result[0]['username'].encode('utf-8'), '1', 'name', result[0]['realname'].encode('utf-8'))) except: print 'failed executing session-attribute sql' self.db().commit() # insert the user's email into session attribute table try: c.execute( """INSERT INTO session_attribute (sid, authenticated, name, value) VALUES (%s, %s, %s, %s)""", (result[0]['username'].encode('utf-8'), '1', 'email', result[0]['email'].encode('utf-8'))) except: print 'failed executing session-attribute sql2' self.db().commit() else: print 'warning: unknown mantis userid %d, recording as anonymous' % userid loginName = '' self.loginNameCache[userid] = loginName elif userid is None or userid == '': self.loginNameCache[userid] = '' return self.loginNameCache[userid] def get_attachments_dir(self,bugid=0): if bugid > 0: return 'importfiles/%i/' % bugid else: return 'importfiles/' def _mkdir(newdir): """works the way a good mkdir should :) - already exists, silently complete - regular file in the way, raise an exception - parent directory(ies) does not exist, make them as well """ if os.path.isdir(newdir): pass elif os.path.isfile(newdir): raise OSError("a file with the same name as the desired " \ "dir, '%s', already exists." % newdir) else: head, tail = os.path.split(newdir) if head and not os.path.isdir(head): _mkdir(head) #print "_mkdir %s" % repr(newdir) if tail: os.mkdir(newdir)