| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| |
| import logging |
| import sys |
| |
| from ming.orm import ThreadLocalORMSession |
| import mock |
| from pylons import tmpl_context as c, app_globals as g |
| |
| from allura import model as M |
| from forgediscussion import model as DM |
| from forgetracker import model as TM |
| |
| from allura.lib import utils |
| |
| log = logging.getLogger(__name__) |
| |
| |
| def public(obj, project=None): |
| if not project: |
| project = obj |
| role_anon = M.ProjectRole.by_name(name='*anonymous', project=project) |
| if not role_anon: |
| log.info('Missing *anonymous role for project "%s"' % |
| project.shortname) |
| return False |
| read = M.ACE.allow(role_anon._id, 'read') |
| return read in obj.acl |
| |
| |
| def scrub_project(p, options): |
| log.info('Scrubbing project "%s"' % p.shortname) |
| preamble = options.preamble |
| if not public(p): |
| log.info('%s project "%s"' % (preamble, p.shortname)) |
| if not options.dry_run: |
| p.delete() |
| return |
| for ac in p.app_configs: |
| ac.project = p |
| c.app = p.app_instance(ac) |
| mount_point = ac.options.get('mount_point') |
| tool_name = ac.tool_name.lower() |
| if tool_name in ('admin', 'search', 'profile'): |
| continue |
| if not public(ac, project=p): |
| log.info('%s tool %s/%s on project "%s"' % ( |
| preamble, tool_name, mount_point, p.shortname)) |
| if not options.dry_run: |
| p.uninstall_app(mount_point) |
| continue |
| q = dict(app_config_id=ac._id) |
| ace = dict(access='DENY', permission='*', role_id=None) |
| q['acl'] = {'$in': [ace]} |
| counter = 0 |
| if tool_name == 'tickets': |
| if ac.options.get('TicketMonitoringEmail'): |
| log.info('%s options.TicketMonitoringEmail from the %s/%s ' |
| 'tool on project "%s"' % (preamble, tool_name, |
| mount_point, p.shortname)) |
| if not options.dry_run: |
| ac.options['TicketMonitoringEmail'] = None |
| for tickets in utils.chunked_find(TM.Ticket, q): |
| for t in tickets: |
| counter += 1 |
| if not options.dry_run: |
| t.discussion_thread.delete() |
| t.delete() |
| ThreadLocalORMSession.flush_all() |
| ThreadLocalORMSession.close_all() |
| if counter > 0: |
| log.info('%s %s tickets from the %s/%s tool on ' |
| 'project "%s"' % (preamble, counter, tool_name, |
| mount_point, p.shortname)) |
| elif tool_name == 'discussion': |
| for forums in utils.chunked_find(DM.Forum, q): |
| for f in forums: |
| counter += 1 |
| if not options.dry_run: |
| f.delete() |
| if counter > 0: |
| log.info('%s %s forums from the %s/%s tool on ' |
| 'project "%s"' % (preamble, counter, tool_name, |
| mount_point, p.shortname)) |
| |
| |
| def main(options): |
| log.addHandler(logging.StreamHandler(sys.stdout)) |
| log.setLevel(getattr(logging, options.log_level.upper())) |
| |
| g.solr = mock.Mock() |
| preamble = options.dry_run and "Would delete" or "Deleting" |
| options.preamble = preamble |
| |
| for nbhd in M.Neighborhood.query.find(): |
| q = {'neighborhood_id': nbhd._id} |
| for projects in utils.chunked_find(M.Project, q): |
| for p in projects: |
| scrub_project(p, options) |
| ThreadLocalORMSession.flush_all() |
| ThreadLocalORMSession.close_all() |
| |
| log.info('%s %s EmailAddress documents' % |
| (preamble, M.EmailAddress.query.find().count())) |
| log.info('%s email addresses from %s User documents' % |
| (preamble, M.User.query.find().count())) |
| log.info('%s monitoring_email addresses from %s Forum documents' % |
| (preamble, DM.Forum.query.find({"monitoring_email": |
| {"$nin": [None, ""]}}).count())) |
| |
| if not options.dry_run: |
| M.EmailAddress.query.remove() |
| M.User.query.update({}, {"$set": {"email_addresses": []}}, multi=True) |
| DM.Forum.query.update({"monitoring_email": {"$nin": [None, ""]}}, |
| {"$set": {"monitoring_email": None}}, multi=True) |
| return 0 |
| |
| |
| def parse_options(): |
| import argparse |
| parser = argparse.ArgumentParser( |
| description='Removes private data from the Allura MongoDB.') |
| parser.add_argument('--dry-run', dest='dry_run', default=False, |
| action='store_true', |
| help='Run in test mode (no updates will be applied).') |
| parser.add_argument('--log', dest='log_level', default='INFO', |
| help='Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL).') |
| return parser.parse_args() |
| |
| if __name__ == '__main__': |
| sys.exit(main(parse_options())) |