diff options
Diffstat (limited to 'mediagoblin/gmg_commands')
-rw-r--r-- | mediagoblin/gmg_commands/__init__.py | 108 | ||||
-rw-r--r-- | mediagoblin/gmg_commands/assetlink.py | 151 | ||||
-rw-r--r-- | mediagoblin/gmg_commands/dbupdate.py | 132 | ||||
-rw-r--r-- | mediagoblin/gmg_commands/import_export.py | 254 | ||||
-rw-r--r-- | mediagoblin/gmg_commands/shell.py | 76 | ||||
-rw-r--r-- | mediagoblin/gmg_commands/users.py | 103 | ||||
-rw-r--r-- | mediagoblin/gmg_commands/util.py | 40 |
7 files changed, 864 insertions, 0 deletions
diff --git a/mediagoblin/gmg_commands/__init__.py b/mediagoblin/gmg_commands/__init__.py new file mode 100644 index 00000000..d8156126 --- /dev/null +++ b/mediagoblin/gmg_commands/__init__.py @@ -0,0 +1,108 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import argparse +import os + +from mediagoblin.tools.common import import_component + + +SUBCOMMAND_MAP = { + 'shell': { + 'setup': 'mediagoblin.gmg_commands.shell:shell_parser_setup', + 'func': 'mediagoblin.gmg_commands.shell:shell', + 'help': 'Run a shell with some tools pre-setup'}, + 'adduser': { + 'setup': 'mediagoblin.gmg_commands.users:adduser_parser_setup', + 'func': 'mediagoblin.gmg_commands.users:adduser', + 'help': 'Creates an user'}, + 'makeadmin': { + 'setup': 'mediagoblin.gmg_commands.users:makeadmin_parser_setup', + 'func': 'mediagoblin.gmg_commands.users:makeadmin', + 'help': 'Makes user an admin'}, + 'changepw': { + 'setup': 'mediagoblin.gmg_commands.users:changepw_parser_setup', + 'func': 'mediagoblin.gmg_commands.users:changepw', + 'help': 'Changes a user\'s password'}, + 'dbupdate': { + 'setup': 'mediagoblin.gmg_commands.dbupdate:dbupdate_parse_setup', + 'func': 'mediagoblin.gmg_commands.dbupdate:dbupdate', + 'help': 'Set up or update the SQL database'}, + 'assetlink': { + 'setup': 'mediagoblin.gmg_commands.assetlink:assetlink_parser_setup', + 'func': 'mediagoblin.gmg_commands.assetlink:assetlink', + 'help': 'Link assets for themes and plugins for static serving'}, + # 'theme': { + # 'setup': 'mediagoblin.gmg_commands.theme:theme_parser_setup', + # 'func': 'mediagoblin.gmg_commands.theme:theme', + # 'help': 'Theming commands', + # } + + ## These might be useful, mayyyybe, but don't really work anymore + ## due to mongo change and the "versatility" of sql options. + ## + ## For now, commenting out. Might re-enable soonish? + # + # 'env_export': { + # 'setup': 'mediagoblin.gmg_commands.import_export:import_export_parse_setup', + # 'func': 'mediagoblin.gmg_commands.import_export:env_export', + # 'help': 'Exports the data for this MediaGoblin instance'}, + # 'env_import': { + # 'setup': 'mediagoblin.gmg_commands.import_export:import_export_parse_setup', + # 'func': 'mediagoblin.gmg_commands.import_export:env_import', + # 'help': 'Imports the data for this MediaGoblin instance'}, + } + + +def main_cli(): + parser = argparse.ArgumentParser( + description='GNU MediaGoblin utilities.') + parser.add_argument( + '-cf', '--conf_file', default=None, + help=( + "Config file used to set up environment. " + "Default to mediagoblin_local.ini if readable, " + "otherwise mediagoblin.ini")) + + subparsers = parser.add_subparsers(help='sub-command help') + for command_name, command_struct in SUBCOMMAND_MAP.iteritems(): + if 'help' in command_struct: + subparser = subparsers.add_parser( + command_name, help=command_struct['help']) + else: + subparser = subparsers.add_parser(command_name) + + setup_func = import_component(command_struct['setup']) + exec_func = import_component(command_struct['func']) + + setup_func(subparser) + + subparser.set_defaults(func=exec_func) + + args = parser.parse_args() + args.orig_conf_file = args.conf_file + if args.conf_file is None: + if os.path.exists('mediagoblin_local.ini') \ + and os.access('mediagoblin_local.ini', os.R_OK): + args.conf_file = 'mediagoblin_local.ini' + else: + args.conf_file = 'mediagoblin.ini' + + args.func(args) + + +if __name__ == '__main__': + main_cli() diff --git a/mediagoblin/gmg_commands/assetlink.py b/mediagoblin/gmg_commands/assetlink.py new file mode 100644 index 00000000..148ebe9e --- /dev/null +++ b/mediagoblin/gmg_commands/assetlink.py @@ -0,0 +1,151 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os + +from mediagoblin import mg_globals +from mediagoblin.init import setup_global_and_app_config +from mediagoblin.gmg_commands import util as commands_util +from mediagoblin.tools.theme import register_themes +from mediagoblin.tools.translate import pass_to_ugettext as _ +from mediagoblin.tools.common import simple_printer +from mediagoblin.tools import pluginapi + + +def assetlink_parser_setup(subparser): + # theme_subparsers = subparser.add_subparsers( + # dest=u"subcommand", + # help=u'Assetlink options') + + # # Install command + # install_parser = theme_subparsers.add_parser( + # u'install', help=u'Install a theme to this mediagoblin instance') + # install_parser.add_argument( + # u'themefile', help=u'The theme archive to be installed') + + # theme_subparsers.add_parser( + # u'assetlink', + # help=( + # u"Link the currently installed theme's assets " + # u"to the served theme asset directory")) + pass + + +########### +# Utilities +########### + +def link_theme_assets(theme, link_dir, printer=simple_printer): + """ + Returns a list of string of text telling the user what we did + which should be printable. + """ + link_dir = link_dir.rstrip(os.path.sep) + link_parent_dir = os.path.dirname(link_dir) + + if theme is None: + printer(_("Cannot link theme... no theme set\n")) + return + + def _maybe_unlink_link_dir(): + """unlink link directory if it exists""" + if os.path.lexists(link_dir) \ + and os.path.islink(link_dir): + os.unlink(link_dir) + return True + + return + + if theme.get('assets_dir') is None: + printer(_("No asset directory for this theme\n")) + if _maybe_unlink_link_dir(): + printer( + _("However, old link directory symlink found; removed.\n")) + return + + _maybe_unlink_link_dir() + + # make the link directory parent dirs if necessary + if not os.path.lexists(link_parent_dir): + os.makedirs(link_parent_dir) + + os.symlink( + theme['assets_dir'].rstrip(os.path.sep), + link_dir) + printer("Linked the theme's asset directory:\n %s\nto:\n %s\n" % ( + theme['assets_dir'], link_dir)) + + +def link_plugin_assets(plugin_static, plugins_link_dir, printer=simple_printer): + """ + Arguments: + - plugin_static: a mediagoblin.tools.staticdirect.PluginStatic instance + representing the static assets of this plugins' configuration + - plugins_link_dir: Base directory plugins are linked from + """ + # link_dir is the final directory we'll link to, a combination of + # the plugin assetlink directory and plugin_static.name + link_dir = os.path.join( + plugins_link_dir.rstrip(os.path.sep), plugin_static.name) + + # make the link directory parent dirs if necessary + if not os.path.lexists(plugins_link_dir): + os.makedirs(plugins_link_dir) + + # See if the link_dir already exists. + if os.path.lexists(link_dir): + # if this isn't a symlink, there's something wrong... error out. + if not os.path.islink(link_dir): + printer(_('Could not link "%s": %s exists and is not a symlink\n') % ( + plugin_static.name, link_dir)) + return + + # if this is a symlink and the path already exists, skip it. + if os.path.realpath(link_dir) == plugin_static.file_path: + # Is this comment helpful or not? + printer(_('Skipping "%s"; already set up.\n') % ( + plugin_static.name)) + return + + # Otherwise, it's a link that went to something else... unlink it + printer(_('Old link found for "%s"; removing.\n') % ( + plugin_static.name)) + os.unlink(link_dir) + + os.symlink( + plugin_static.file_path.rstrip(os.path.sep), + link_dir) + printer('Linked asset directory for plugin "%s":\n %s\nto:\n %s\n' % ( + plugin_static.name, + plugin_static.file_path.rstrip(os.path.sep), + link_dir)) + + +def assetlink(args): + """ + Link the asset directory of the currently installed theme and plugins + """ + mgoblin_app = commands_util.setup_app(args) + app_config = mg_globals.app_config + + # link theme + link_theme_assets(mgoblin_app.current_theme, app_config['theme_linked_assets_dir']) + + # link plugin assets + ## ... probably for this we need the whole application initialized + for plugin_static in pluginapi.hook_runall("static_setup"): + link_plugin_assets( + plugin_static, app_config['plugin_linked_assets_dir']) diff --git a/mediagoblin/gmg_commands/dbupdate.py b/mediagoblin/gmg_commands/dbupdate.py new file mode 100644 index 00000000..fa25ecb2 --- /dev/null +++ b/mediagoblin/gmg_commands/dbupdate.py @@ -0,0 +1,132 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import logging + +from sqlalchemy.orm import sessionmaker + +from mediagoblin.db.open import setup_connection_and_db_from_config +from mediagoblin.db.migration_tools import MigrationManager +from mediagoblin.init import setup_global_and_app_config +from mediagoblin.tools.common import import_component + +_log = logging.getLogger(__name__) +logging.basicConfig() +_log.setLevel(logging.DEBUG) + +def dbupdate_parse_setup(subparser): + pass + + +class DatabaseData(object): + def __init__(self, name, models, migrations): + self.name = name + self.models = models + self.migrations = migrations + + def make_migration_manager(self, session): + return MigrationManager( + self.name, self.models, self.migrations, session) + + +def gather_database_data(media_types, plugins): + """ + Gather all database data relevant to the extensions we have + installed so we can do migrations and table initialization. + + Returns a list of DatabaseData objects. + """ + managed_dbdata = [] + + # Add main first + from mediagoblin.db.models import MODELS as MAIN_MODELS + from mediagoblin.db.migrations import MIGRATIONS as MAIN_MIGRATIONS + + managed_dbdata.append( + DatabaseData( + u'__main__', MAIN_MODELS, MAIN_MIGRATIONS)) + + # Then get all registered media managers (eventually, plugins) + for media_type in media_types: + models = import_component('%s.models:MODELS' % media_type) + migrations = import_component('%s.migrations:MIGRATIONS' % media_type) + managed_dbdata.append( + DatabaseData(media_type, models, migrations)) + + for plugin in plugins: + try: + models = import_component('{0}.models:MODELS'.format(plugin)) + except ImportError as exc: + _log.debug('No models found for {0}: {1}'.format( + plugin, + exc)) + + models = [] + except AttributeError as exc: + _log.warning('Could not find MODELS in {0}.models, have you \ +forgotten to add it? ({1})'.format(plugin, exc)) + models = [] + + try: + migrations = import_component('{0}.migrations:MIGRATIONS'.format( + plugin)) + except ImportError as exc: + _log.debug('No migrations found for {0}: {1}'.format( + plugin, + exc)) + + migrations = {} + except AttributeError as exc: + _log.debug('Cloud not find MIGRATIONS in {0}.migrations, have you \ +forgotten to add it? ({1})'.format(plugin, exc)) + migrations = {} + + if models: + managed_dbdata.append( + DatabaseData(plugin, models, migrations)) + + + return managed_dbdata + + +def run_dbupdate(app_config, global_config): + """ + Initialize or migrate the database as specified by the config file. + + Will also initialize or migrate all extensions (media types, and + in the future, plugins) + """ + + # Gather information from all media managers / projects + dbdatas = gather_database_data( + app_config['media_types'], + global_config.get('plugins', {}).keys()) + + # Set up the database + db = setup_connection_and_db_from_config(app_config, migrations=True) + + Session = sessionmaker(bind=db.engine) + + # Setup media managers for all dbdata, run init/migrate and print info + # For each component, create/migrate tables + for dbdata in dbdatas: + migration_manager = dbdata.make_migration_manager(Session()) + migration_manager.init_or_migrate() + + +def dbupdate(args): + global_config, app_config = setup_global_and_app_config(args.conf_file) + run_dbupdate(app_config, global_config) diff --git a/mediagoblin/gmg_commands/import_export.py b/mediagoblin/gmg_commands/import_export.py new file mode 100644 index 00000000..d51a1e3e --- /dev/null +++ b/mediagoblin/gmg_commands/import_export.py @@ -0,0 +1,254 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from mediagoblin import mg_globals +from mediagoblin.db.open import setup_connection_and_db_from_config +from mediagoblin.storage.filestorage import BasicFileStorage +from mediagoblin.init import setup_storage, setup_global_and_app_config + +import shutil +import tarfile +import tempfile +import subprocess +import os.path +import os +import sys +import logging +from contextlib import closing + +_log = logging.getLogger('gmg.import_export') +logging.basicConfig() +_log.setLevel(logging.INFO) + + +def import_export_parse_setup(subparser): + # TODO: Add default + subparser.add_argument( + 'tar_file') + subparser.add_argument( + '--mongodump_path', default='mongodump', + help='mongodump binary') + subparser.add_argument( + '--mongorestore_path', default='mongorestore', + help='mongorestore binary') + subparser.add_argument( + '--cache_path', + help='Temporary directory where files will be temporarily dumped') + + +def _import_media(db, args): + ''' + Import media files + + Must be called after _import_database() + ''' + _log.info('-> Importing media...') + + media_cache = BasicFileStorage( + args._cache_path['media']) + + # TODO: Add import of queue files + queue_cache = BasicFileStorage(args._cache_path['queue']) + + for entry in db.MediaEntry.find(): + for name, path in entry.media_files.items(): + _log.info('Importing: {0} - {1}'.format( + entry.title.encode('ascii', 'replace'), + name)) + + media_file = mg_globals.public_store.get_file(path, mode='wb') + media_file.write( + media_cache.get_file(path, mode='rb').read()) + + _log.info('...Media imported') + + +def _import_database(db, args): + ''' + Restore mongo database from ___.bson files + ''' + _log.info('-> Importing database...') + + p = subprocess.Popen([ + args.mongorestore_path, + '-d', db.name, + os.path.join(args._cache_path['database'], db.name)]) + + p.wait() + + _log.info('...Database imported') + + +def env_import(args): + ''' + Restore mongo database and media files from a tar archive + ''' + if not args.cache_path: + args.cache_path = tempfile.mkdtemp() + + setup_global_and_app_config(args.conf_file) + + # Creates mg_globals.public_store and mg_globals.queue_store + setup_storage() + + global_config, app_config = setup_global_and_app_config(args.conf_file) + db = setup_connection_and_db_from_config( + app_config) + + tf = tarfile.open( + args.tar_file, + mode='r|gz') + + tf.extractall(args.cache_path) + + args.cache_path = os.path.join( + args.cache_path, 'mediagoblin-data') + args = _setup_paths(args) + + # Import database from extracted data + _import_database(db, args) + + _import_media(db, args) + + _clean(args) + + +def _setup_paths(args): + ''' + Populate ``args`` variable with cache subpaths + ''' + args._cache_path = dict() + PATH_MAP = { + 'media': 'media', + 'queue': 'queue', + 'database': 'database'} + + for key, val in PATH_MAP.items(): + args._cache_path[key] = os.path.join(args.cache_path, val) + + return args + + +def _create_archive(args): + ''' + Create the tar archive + ''' + _log.info('-> Compressing to archive') + + tf = tarfile.open( + args.tar_file, + mode='w|gz') + + with closing(tf): + tf.add(args.cache_path, 'mediagoblin-data/') + + _log.info('...Archiving done') + + +def _clean(args): + ''' + Remove cache directory + ''' + shutil.rmtree(args.cache_path) + + +def _export_check(args): + ''' + Run security checks for export command + ''' + if os.path.exists(args.tar_file): + overwrite = raw_input( + 'The output file already exists. ' + 'Are you **SURE** you want to overwrite it? ' + '(yes/no)> ') + if not overwrite == 'yes': + print 'Aborting.' + + return False + + return True + + +def _export_database(db, args): + _log.info('-> Exporting database...') + + p = subprocess.Popen([ + args.mongodump_path, + '-d', db.name, + '-o', args._cache_path['database']]) + + p.wait() + + _log.info('...Database exported') + + +def _export_media(db, args): + _log.info('-> Exporting media...') + + media_cache = BasicFileStorage( + args._cache_path['media']) + + # TODO: Add export of queue files + queue_cache = BasicFileStorage(args._cache_path['queue']) + + for entry in db.MediaEntry.find(): + for name, path in entry.media_files.items(): + _log.info(u'Exporting {0} - {1}'.format( + entry.title, + name)) + try: + mc_file = media_cache.get_file(path, mode='wb') + mc_file.write( + mg_globals.public_store.get_file(path, mode='rb').read()) + except Exception as e: + _log.error('Failed: {0}'.format(e)) + + _log.info('...Media exported') + + +def env_export(args): + ''' + Export database and media files to a tar archive + ''' + if args.cache_path: + if os.path.exists(args.cache_path): + _log.error('The cache directory must not exist ' + 'before you run this script') + _log.error('Cache directory: {0}'.format(args.cache_path)) + + return False + else: + args.cache_path = tempfile.mkdtemp() + + args = _setup_paths(args) + + if not _export_check(args): + _log.error('Checks did not pass, exiting') + sys.exit(0) + + globa_config, app_config = setup_global_and_app_config(args.conf_file) + + setup_storage() + + db = setup_connection_and_db_from_config(app_config) + + _export_database(db, args) + + _export_media(db, args) + + _create_archive(args) + + _clean(args) diff --git a/mediagoblin/gmg_commands/shell.py b/mediagoblin/gmg_commands/shell.py new file mode 100644 index 00000000..4998acd7 --- /dev/null +++ b/mediagoblin/gmg_commands/shell.py @@ -0,0 +1,76 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +import code + +from mediagoblin import mg_globals +from mediagoblin.gmg_commands import util as commands_util + + +def shell_parser_setup(subparser): + subparser.add_argument( + '--ipython', help='Use ipython', + action="store_true") + + +SHELL_BANNER = """\ +GNU MediaGoblin shell! +---------------------- +Available vars: + - mgoblin_app: instantiated mediagoblin application + - mg_globals: mediagoblin.globals + - db: database instance +""" + +def py_shell(**user_namespace): + """ + Run a shell using normal python shell. + """ + code.interact( + banner=SHELL_BANNER, + local=user_namespace) + + +def ipython_shell(**user_namespace): + """ + Run a shell for the user using ipython. Return False if there is no IPython + """ + try: + from IPython import embed + except: + return False + + embed( + banner1=SHELL_BANNER, + user_ns=user_namespace) + return True + +def shell(args): + """ + Setup a shell for the user either a normal Python shell or an IPython one + """ + user_namespace = { + 'mg_globals': mg_globals, + 'mgoblin_app': commands_util.setup_app(args), + 'db': mg_globals.database} + + if args.ipython: + ipython_shell(**user_namespace) + else: + # Try ipython_shell first and fall back if not available + if not ipython_shell(**user_namespace): + py_shell(**user_namespace) diff --git a/mediagoblin/gmg_commands/users.py b/mediagoblin/gmg_commands/users.py new file mode 100644 index 00000000..024c8498 --- /dev/null +++ b/mediagoblin/gmg_commands/users.py @@ -0,0 +1,103 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from mediagoblin.gmg_commands import util as commands_util +from mediagoblin.auth import lib as auth_lib +from mediagoblin import mg_globals + +def adduser_parser_setup(subparser): + subparser.add_argument( + '--username','-u', + help="Username used to login") + subparser.add_argument( + '--password','-p', + help="Your supersecret word to login, beware of storing it in bash history") + subparser.add_argument( + '--email','-e', + help="Email to receive notifications") + + +def adduser(args): + #TODO: Lets trust admins this do not validate Emails :) + commands_util.setup_app(args) + + args.username = commands_util.prompt_if_not_set(args.username, "Username:") + args.password = commands_util.prompt_if_not_set(args.password, "Password:",True) + args.email = commands_util.prompt_if_not_set(args.email, "Email:") + + db = mg_globals.database + users_with_username = \ + db.User.find({ + 'username': args.username.lower(), + }).count() + + if users_with_username: + print u'Sorry, a user with that name already exists.' + + else: + # Create the user + entry = db.User() + entry.username = unicode(args.username.lower()) + entry.email = unicode(args.email) + entry.pw_hash = auth_lib.bcrypt_gen_password_hash(args.password) + entry.status = u'active' + entry.email_verified = True + entry.save() + + print "User created (and email marked as verified)" + + +def makeadmin_parser_setup(subparser): + subparser.add_argument( + 'username', + help="Username to give admin level") + + +def makeadmin(args): + commands_util.setup_app(args) + + db = mg_globals.database + + user = db.User.one({'username': unicode(args.username.lower())}) + if user: + user.is_admin = True + user.save() + print 'The user is now Admin' + else: + print 'The user doesn\'t exist' + + +def changepw_parser_setup(subparser): + subparser.add_argument( + 'username', + help="Username used to login") + subparser.add_argument( + 'password', + help="Your NEW supersecret word to login") + + +def changepw(args): + commands_util.setup_app(args) + + db = mg_globals.database + + user = db.User.one({'username': unicode(args.username.lower())}) + if user: + user.pw_hash = auth_lib.bcrypt_gen_password_hash(args.password) + user.save() + print 'Password successfully changed' + else: + print 'The user doesn\'t exist' diff --git a/mediagoblin/gmg_commands/util.py b/mediagoblin/gmg_commands/util.py new file mode 100644 index 00000000..6a6853d5 --- /dev/null +++ b/mediagoblin/gmg_commands/util.py @@ -0,0 +1,40 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +from mediagoblin import app +import getpass + + +def setup_app(args): + """ + Setup the application after reading the mediagoblin config files + """ + mgoblin_app = app.MediaGoblinApp(args.conf_file) + + return mgoblin_app + +def prompt_if_not_set(variable, text, password=False): + """ + Checks if the variable is None and prompt for a value if it is + """ + if variable is None: + if not password: + variable=raw_input(text + u' ') + else: + variable=getpass.getpass(text + u' ') + + return variable |