Use upstream logic for install command, and some web menus
This commit is contained in:
		
							parent
							
								
									617515a167
								
							
						
					
					
						commit
						c66d0ababa
					
				
					 6 changed files with 74 additions and 453 deletions
				
			
		|  | @ -25,15 +25,10 @@ Messkit commands | |||
| """ | ||||
| 
 | ||||
| import os | ||||
| import stat | ||||
| import sys | ||||
| import subprocess | ||||
| 
 | ||||
| import sqlalchemy as sa | ||||
| from alembic.util.messaging import obfuscate_url_pw | ||||
| 
 | ||||
| from rattail import commands | ||||
| from rattail.files import resource_path | ||||
| 
 | ||||
| from messkit import __version__ | ||||
| 
 | ||||
|  | @ -57,203 +52,67 @@ class Command(commands.Command): | |||
|     long_description = '' | ||||
| 
 | ||||
| 
 | ||||
| class Install(commands.Subcommand): | ||||
| class Install(commands.InstallSubcommand): | ||||
|     """ | ||||
|     Install a Messkit app | ||||
|     Install the Messkit app | ||||
|     """ | ||||
|     name = 'install' | ||||
|     description = __doc__.strip() | ||||
| 
 | ||||
|     def run(self, args): | ||||
|     # nb. these must be explicitly set b/c config is not available | ||||
|     # when running normally, e.g. `messkit -n install` | ||||
|     app_title = "Messkit" | ||||
|     app_package = 'messkit' | ||||
|     app_eggname = 'Messkit' | ||||
|     app_pypiname = 'Messkit' | ||||
| 
 | ||||
|         self.rprint("\n\t[blue]Welcome to Messkit![/blue]") | ||||
|         self.rprint("\n\tThis tool will install and configure a new app.") | ||||
|         self.rprint("\n\t[italic]NB. You should already have created a new database in PostgreSQL or MySQL.[/italic]") | ||||
|     def do_install_steps(self): | ||||
| 
 | ||||
|         # continue? | ||||
|         if not self.basic_prompt("continue?", True, is_bool=True): | ||||
|             self.rprint() | ||||
|             sys.exit(0) | ||||
|         # first all normal steps | ||||
|         super(Install, self).do_install_steps() | ||||
| 
 | ||||
|         # appdir must not yet exist | ||||
|         appdir = os.path.join(sys.prefix, 'app') | ||||
|         if os.path.exists(appdir): | ||||
|             self.rprint("\n\t[bold red]appdir already exists:[/bold red]  {}\n".format(appdir)) | ||||
|             sys.exit(1) | ||||
|         # we also install poser..for now..? | ||||
|         self.install_poser() | ||||
| 
 | ||||
|         # get db info | ||||
|         dbtype = self.basic_prompt('db type', 'postgresql') | ||||
|         dbhost = self.basic_prompt('db host', 'localhost') | ||||
|         dbport = self.basic_prompt('db port', '3306' if dbtype == 'mysql' else '5432') | ||||
|         dbname = self.basic_prompt('db name', 'messkit') | ||||
|         dbuser = self.basic_prompt('db user', 'rattail') | ||||
|     def put_settings(self, **kwargs): | ||||
| 
 | ||||
|         # get db password | ||||
|         dbpass = None | ||||
|         while not dbpass: | ||||
|             dbpass = self.basic_prompt('db pass', is_password=True) | ||||
|         rattail = [os.path.join(sys.prefix, 'bin', 'rattail'), | ||||
|                    '-c', os.path.join(sys.prefix, 'app', 'silent.conf')] | ||||
| 
 | ||||
|         # test db connection | ||||
|         self.rprint("\n\ttesting db connection... ", end='') | ||||
|         dburl = self.make_db_url(dbtype, dbhost, dbport, dbname, dbuser, dbpass) | ||||
|         error = self.test_db_connection(dburl) | ||||
|         if error: | ||||
|             self.rprint("[bold red]cannot connect![/bold red] ..error was:") | ||||
|             self.rprint("\n{}".format(error)) | ||||
|             self.rprint("\n\t[bold yellow]aborting mission[/bold yellow]\n") | ||||
|             sys.exit(1) | ||||
|         self.rprint("[bold green]good[/bold green]") | ||||
|         # set falafel theme | ||||
|         cmd = rattail + ['setting-put', 'tailbone.theme', 'falafel'] | ||||
|         subprocess.check_call(cmd) | ||||
| 
 | ||||
|         # make the appdir | ||||
|         self.app.make_appdir(appdir) | ||||
|         # hide theme picker | ||||
|         cmd = rattail + ['setting-put', 'tailbone.themes.expose_picker', 'false'] | ||||
|         subprocess.check_call(cmd) | ||||
| 
 | ||||
|         # shared context for generated app files | ||||
|         context = { | ||||
|             'envdir': sys.prefix, | ||||
|             'app_package': 'messkit', | ||||
|             'app_title': "Messkit", | ||||
|             'appdir': appdir, | ||||
|             'db_url': dburl, | ||||
|             'pyramid_egg': 'Messkit', | ||||
|             'beaker_key': 'messkit', | ||||
|         } | ||||
|         # set main image | ||||
|         cmd = rattail + ['setting-put', 'tailbone.main_image_url', '/messkit/img/messkit.png'] | ||||
|         subprocess.check_call(cmd) | ||||
| 
 | ||||
|         # make config files | ||||
|         rattail_conf = self.app.make_config_file( | ||||
|             'rattail', os.path.join(appdir, 'rattail.conf'), | ||||
|             template_path=resource_path('messkit:templates/installer/rattail.conf.mako'), | ||||
|             **context) | ||||
|         quiet_conf = self.app.make_config_file('quiet', appdir) | ||||
|         web_conf = self.app.make_config_file( | ||||
|             'web-complete', os.path.join(appdir, 'web.conf'), | ||||
|             **context) | ||||
|         # set header image | ||||
|         cmd = rattail + ['setting-put', 'tailbone.header_image_url', '/messkit/img/messkit-small.png'] | ||||
|         subprocess.check_call(cmd) | ||||
| 
 | ||||
|         # make upgrade script | ||||
|         path = os.path.join(appdir, 'upgrade.sh') | ||||
|         self.app.render_mako_template( | ||||
|             resource_path('messkit:templates/installer/upgrade.sh.mako'), | ||||
|             context, output_path=path) | ||||
|         os.chmod(path, stat.S_IRWXU | ||||
|                  | stat.S_IRGRP | ||||
|                  | stat.S_IXGRP | ||||
|                  | stat.S_IROTH | ||||
|                  | stat.S_IXOTH) | ||||
|         # set favicon image | ||||
|         cmd = rattail + ['setting-put', 'tailbone.favicon_url', '/messkit/img/messkit-small.png'] | ||||
|         subprocess.check_call(cmd) | ||||
| 
 | ||||
|         self.rprint("\n\tappdir created at:  [bold green]{}[/bold green]".format(appdir)) | ||||
|         # set default grid page size | ||||
|         cmd = rattail + ['setting-put', 'tailbone.grid.default_pagesize', '20'] | ||||
|         subprocess.check_call(cmd) | ||||
| 
 | ||||
|         bindir = os.path.join(sys.prefix, 'bin') | ||||
| 
 | ||||
|         schema_installed = False | ||||
|         if self.basic_prompt("install db schema?", True, is_bool=True): | ||||
|             self.rprint() | ||||
| 
 | ||||
|             # install db schema | ||||
|             alembic = os.path.join(bindir, 'alembic') | ||||
|             cmd = [alembic, '-c', rattail_conf, 'upgrade', 'heads'] | ||||
|             subprocess.check_call(cmd) | ||||
|             schema_installed = True | ||||
| 
 | ||||
|             rattail = os.path.join(bindir, 'rattail') | ||||
| 
 | ||||
|             # set falafel theme | ||||
|             cmd = [rattail, '-c', quiet_conf, '--no-versioning', | ||||
|                    'setting-put', 'tailbone.theme', 'falafel'] | ||||
|             subprocess.check_call(cmd) | ||||
| 
 | ||||
|             # set main image | ||||
|             cmd = [rattail, '-c', quiet_conf, '--no-versioning', | ||||
|                    'setting-put', 'tailbone.main_image_url', '/messkit/img/messkit.png'] | ||||
|             subprocess.check_call(cmd) | ||||
| 
 | ||||
|             # set header image | ||||
|             cmd = [rattail, '-c', quiet_conf, '--no-versioning', | ||||
|                    'setting-put', 'tailbone.header_image_url', '/messkit/img/messkit-small.png'] | ||||
|             subprocess.check_call(cmd) | ||||
| 
 | ||||
|             # set favicon image | ||||
|             cmd = [rattail, '-c', quiet_conf, '--no-versioning', | ||||
|                    'setting-put', 'tailbone.favicon_url', '/messkit/img/messkit-small.png'] | ||||
|             subprocess.check_call(cmd) | ||||
| 
 | ||||
|             self.rprint("\n\tdb schema installed to:  [bold green]{}[/bold green]".format( | ||||
|                 obfuscate_url_pw(dburl))) | ||||
| 
 | ||||
|             if self.basic_prompt("create admin user?", True, is_bool=True): | ||||
| 
 | ||||
|                 # get admin credentials | ||||
|                 username = self.basic_prompt('admin username', 'admin') | ||||
|                 password = None | ||||
|                 while not password: | ||||
|                     password = self.basic_prompt('admin password', is_password=True) | ||||
|                     if password: | ||||
|                         confirm = self.basic_prompt('confirm password', is_password=True) | ||||
|                         if not confirm or confirm != password: | ||||
|                             self.rprint("[bold yellow]passwords did not match[/bold yellow]") | ||||
|                             password = None | ||||
|                 fullname = self.basic_prompt('full name') | ||||
| 
 | ||||
|                 self.rprint() | ||||
| 
 | ||||
|                 # make admin user | ||||
|                 rattail = os.path.join(bindir, 'rattail') | ||||
|                 cmd = [rattail, '-c', quiet_conf, 'make-user', '-A', username, | ||||
|                        '--password', password] | ||||
|                 if fullname: | ||||
|                     cmd.extend(['--full-name', fullname]) | ||||
|                 subprocess.check_call(cmd) | ||||
| 
 | ||||
|                 self.rprint("\n\tadmin user created:  [bold green]{}[/bold green]".format( | ||||
|                     username)) | ||||
| 
 | ||||
|         if self.basic_prompt("make poser dir?", True, is_bool=True): | ||||
|             self.rprint() | ||||
| 
 | ||||
|             # make poser dir | ||||
|             poser_handler = self.app.get_poser_handler() | ||||
|             poserdir = poser_handler.make_poser_dir() | ||||
| 
 | ||||
|             self.rprint("\n\tposer dir created:  [bold green]{}[/bold green]".format( | ||||
|                 poserdir)) | ||||
| 
 | ||||
|         self.rprint("\n\t[bold green]initial setup is complete![/bold green]") | ||||
| 
 | ||||
|         if schema_installed: | ||||
|             self.rprint("\n\tyou can run the web app with this command:") | ||||
|             pserve = os.path.join(bindir, 'pserve') | ||||
|             self.rprint("\n\t[blue]{} file+ini:{}[/blue]".format(pserve, web_conf)) | ||||
|     def install_poser(self): | ||||
|         if not self.basic_prompt("make poser dir?", True, is_bool=True): | ||||
|             return False | ||||
| 
 | ||||
|         self.rprint() | ||||
| 
 | ||||
|         # TODO: somewhere should ask about apache proxy, https etc.? | ||||
|         # make poser dir | ||||
|         poser_handler = self.app.get_poser_handler() | ||||
|         poserdir = poser_handler.make_poser_dir() | ||||
| 
 | ||||
|     def make_db_url(self, dbtype, dbhost, dbport, dbname, dbuser, dbpass): | ||||
|         try: | ||||
|             # newer style | ||||
|             from sqlalchemy.engine import URL | ||||
|             factory = URL.create | ||||
|         except ImportError: | ||||
|             # older style | ||||
|             from sqlalchemy.engine.url import URL | ||||
|             factory = URL | ||||
| 
 | ||||
|         if dbtype == 'mysql': | ||||
|             drivername = 'mysql+mysqlconnector' | ||||
|         else: | ||||
|             drivername = 'postgresql+psycopg2' | ||||
| 
 | ||||
|         return factory(drivername=drivername, | ||||
|                        username=dbuser, | ||||
|                        password=dbpass, | ||||
|                        host=dbhost, | ||||
|                        port=dbport, | ||||
|                        database=dbname) | ||||
| 
 | ||||
|     def test_db_connection(self, url): | ||||
|         engine = sa.create_engine(url) | ||||
| 
 | ||||
|         # check for random table; does not matter if it exists, we | ||||
|         # just need to test interaction and this is a neutral way | ||||
|         try: | ||||
|             engine.has_table('whatever') | ||||
|         except Exception as error: | ||||
|             return str(error) | ||||
|         self.rprint("\n\tposer dir created:  [bold green]{}[/bold green]".format( | ||||
|             poserdir)) | ||||
|         return True | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| ###################################################################### | ||||
| # | ||||
| #  Messkit -- Generic-ish Data Utility App | ||||
| #  Copyright © 2022 Lance Edgar | ||||
| #  Copyright © 2022-2023 Lance Edgar | ||||
| # | ||||
| #  This file is part of Messkit. | ||||
| # | ||||
|  | @ -42,7 +42,7 @@ class MesskitConfig(ConfigExtension): | |||
|         config.setdefault('rattail', 'app_title', "Messkit") | ||||
|         config.setdefault('rattail', 'app_class_prefix', 'Messkit') | ||||
|         config.setdefault('rattail', 'app_table_prefix', 'messkit') | ||||
|         config.setdefault('tailbone', 'menus', 'messkit.web.menus') | ||||
|         config.setdefault('tailbone.menus', 'handler', 'messkit.web.menus:MesskitMenuHandler') | ||||
|         config.setdefault('rattail', 'enum', 'messkit.enum') | ||||
|         config.setdefault('rattail', 'model', 'messkit.db.model') | ||||
|         config.setdefault('rattail.mail', 'emails', 'messkit.emails') | ||||
|  |  | |||
|  | @ -1,146 +0,0 @@ | |||
| ## -*- mode: conf; -*- | ||||
| 
 | ||||
| <%text>############################################################</%text> | ||||
| # | ||||
| # ${app_title} core config | ||||
| # | ||||
| <%text>############################################################</%text> | ||||
| 
 | ||||
| 
 | ||||
| <%text>##############################</%text> | ||||
| # rattail | ||||
| <%text>##############################</%text> | ||||
| 
 | ||||
| [rattail] | ||||
| app_package = ${app_package} | ||||
| timezone.default = ${timezone} | ||||
| appdir = ${appdir} | ||||
| datadir = ${os.path.join(appdir, 'data')} | ||||
| batch.files = ${os.path.join(appdir, 'data', 'batch')} | ||||
| workdir = ${os.path.join(appdir, 'work')} | ||||
| export.files = ${os.path.join(appdir, 'data', 'exports')} | ||||
| 
 | ||||
| [rattail.config] | ||||
| # require = /etc/rattail/rattail.conf | ||||
| configure_logging = true | ||||
| usedb = true | ||||
| preferdb = true | ||||
| 
 | ||||
| [rattail.db] | ||||
| default.url = ${db_url} | ||||
| versioning.enabled = true | ||||
| 
 | ||||
| [rattail.mail] | ||||
| 
 | ||||
| # this is the global email shutoff switch | ||||
| #send_emails = false | ||||
| 
 | ||||
| # recommended setup is to always talk to postfix on localhost and then | ||||
| # it can handle any need complexities, e.g. sending to relay | ||||
| smtp.server = localhost | ||||
| 
 | ||||
| # by default only email templates from rattail proper are used | ||||
| templates = rattail:templates/mail | ||||
| 
 | ||||
| # this is the "default" email profile, from which all others initially | ||||
| # inherit, but most/all profiles will override these values | ||||
| default.prefix = [${app_title}] | ||||
| default.from = rattail@localhost | ||||
| default.to = root@localhost | ||||
| # nb. in test environment it can be useful to disable by default, and | ||||
| # then selectively enable certain (e.g. feedback, upgrade) emails | ||||
| #default.enabled = false | ||||
| 
 | ||||
| [rattail.upgrades] | ||||
| command = ${os.path.join(appdir, 'upgrade.sh')} --verbose | ||||
| files = ${os.path.join(appdir, 'data', 'upgrades')} | ||||
| 
 | ||||
| 
 | ||||
| <%text>##############################</%text> | ||||
| # alembic | ||||
| <%text>##############################</%text> | ||||
| 
 | ||||
| [alembic] | ||||
| script_location = rattail.db:alembic | ||||
| version_locations = rattail.db:alembic/versions | ||||
| 
 | ||||
| 
 | ||||
| <%text>##############################</%text> | ||||
| # logging | ||||
| <%text>##############################</%text> | ||||
| 
 | ||||
| [loggers] | ||||
| keys = root, exc_logger, beaker, txn, sqlalchemy, django_db, flufl_bounce, requests | ||||
| 
 | ||||
| [handlers] | ||||
| keys = file, console, email | ||||
| 
 | ||||
| [formatters] | ||||
| keys = generic, console | ||||
| 
 | ||||
| [logger_root] | ||||
| handlers = file, console | ||||
| level = DEBUG | ||||
| 
 | ||||
| [logger_exc_logger] | ||||
| qualname = exc_logger | ||||
| handlers = email | ||||
| level = ERROR | ||||
| 
 | ||||
| [logger_beaker] | ||||
| qualname = beaker | ||||
| handlers = | ||||
| level = INFO | ||||
| 
 | ||||
| [logger_txn] | ||||
| qualname = txn | ||||
| handlers = | ||||
| level = INFO | ||||
| 
 | ||||
| [logger_sqlalchemy] | ||||
| qualname = sqlalchemy.engine | ||||
| handlers = | ||||
| # handlers = file | ||||
| # level = INFO | ||||
| 
 | ||||
| [logger_django_db] | ||||
| qualname = django.db.backends | ||||
| handlers = | ||||
| level = INFO | ||||
| # level = DEBUG | ||||
| 
 | ||||
| [logger_flufl_bounce] | ||||
| qualname = flufl.bounce | ||||
| handlers = | ||||
| level = WARNING | ||||
| 
 | ||||
| [logger_requests] | ||||
| qualname = requests | ||||
| handlers = | ||||
| # level = WARNING | ||||
| 
 | ||||
| [handler_file] | ||||
| class = handlers.RotatingFileHandler | ||||
| args = (${repr(os.path.join(appdir, 'log', 'rattail.log'))}, 'a', 1000000, 100, 'utf_8') | ||||
| formatter = generic | ||||
| 
 | ||||
| [handler_console] | ||||
| class = StreamHandler | ||||
| args = (sys.stderr,) | ||||
| formatter = console | ||||
| # formatter = generic | ||||
| # level = INFO | ||||
| # level = WARNING | ||||
| 
 | ||||
| [handler_email] | ||||
| class = handlers.SMTPHandler | ||||
| args = ('localhost', 'rattail@localhost', ['root@localhost'], "[Rattail] Logging") | ||||
| formatter = generic | ||||
| level = ERROR | ||||
| 
 | ||||
| [formatter_generic] | ||||
| format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(funcName)s: %(message)s | ||||
| datefmt = %Y-%m-%d %H:%M:%S | ||||
| 
 | ||||
| [formatter_console] | ||||
| format = %(levelname)-5.5s [%(name)s][%(threadName)s] %(funcName)s: %(message)s | ||||
|  | @ -1,29 +0,0 @@ | |||
| #!/bin/sh -e | ||||
| <%text>##################################################</%text> | ||||
| # | ||||
| # upgrade script for ${app_title} app | ||||
| # | ||||
| <%text>##################################################</%text> | ||||
| 
 | ||||
| if [ "$1" = "--verbose" ]; then | ||||
|     VERBOSE='--verbose' | ||||
|     QUIET= | ||||
| else | ||||
|     VERBOSE= | ||||
|     QUIET='--quiet' | ||||
| fi | ||||
| 
 | ||||
| cd ${envdir} | ||||
| 
 | ||||
| PIP='bin/pip' | ||||
| ALEMBIC='bin/alembic' | ||||
| 
 | ||||
| # upgrade pip and friends | ||||
| $PIP install $QUIET --disable-pip-version-check --upgrade pip | ||||
| $PIP install $QUIET --upgrade setuptools wheel | ||||
| 
 | ||||
| # upgrade app proper | ||||
| $PIP install $QUIET --upgrade --upgrade-strategy eager Messkit | ||||
| 
 | ||||
| # migrate schema | ||||
| $ALEMBIC -c app/rattail.conf upgrade heads | ||||
|  | @ -2,7 +2,7 @@ | |||
| ###################################################################### | ||||
| # | ||||
| #  Messkit -- Generic-ish Data Utility App | ||||
| #  Copyright © 2022 Lance Edgar | ||||
| #  Copyright © 2022-2023 Lance Edgar | ||||
| # | ||||
| #  This file is part of Messkit. | ||||
| # | ||||
|  | @ -24,97 +24,36 @@ | |||
| Web Menus | ||||
| """ | ||||
| 
 | ||||
| from tailbone import menus as base | ||||
| 
 | ||||
| def simple_menus(request): | ||||
| 
 | ||||
|     people_menu = { | ||||
|         'title': "People", | ||||
|         'type': 'menu', | ||||
|         'items': [ | ||||
|             { | ||||
|                 'title': "All People", | ||||
|                 'route': 'people', | ||||
|                 'perm': 'people.list', | ||||
|             }, | ||||
|         ], | ||||
|     } | ||||
| class MesskitMenuHandler(base.MenuHandler): | ||||
|     """ | ||||
|     Messkit menu handler | ||||
|     """ | ||||
| 
 | ||||
|     reports_menu = { | ||||
|         'title': "Reports", | ||||
|         'type': 'menu', | ||||
|         'items': [ | ||||
|             { | ||||
|                 'title': "New Report", | ||||
|                 'route': 'report_output.create', | ||||
|                 'perm': 'report_output.create', | ||||
|             }, | ||||
|             { | ||||
|                 'title': "Generated Reports", | ||||
|                 'route': 'report_output', | ||||
|                 'perm': 'report_output.list', | ||||
|             }, | ||||
|             { | ||||
|                 'title': "Problem Reports", | ||||
|                 'route': 'problem_reports', | ||||
|                 'perm': 'problem_reports.list', | ||||
|             }, | ||||
|             {'type': 'sep'}, | ||||
|             { | ||||
|                 'title': "Poser Reports", | ||||
|                 'route': 'poser_reports', | ||||
|                 'perm': 'poser_reports.list', | ||||
|             }, | ||||
|         ], | ||||
|     } | ||||
|     def make_menus(self, request, **kwargs): | ||||
| 
 | ||||
|     admin_menu = { | ||||
|         'title': "Admin", | ||||
|         'type': 'menu', | ||||
|         'items': [ | ||||
|             { | ||||
|                 'title': "Users", | ||||
|                 'route': 'users', | ||||
|                 'perm': 'users.list', | ||||
|             }, | ||||
|             { | ||||
|                 'title': "Roles", | ||||
|                 'route': 'roles', | ||||
|                 'perm': 'roles.list', | ||||
|             }, | ||||
|             {'type': 'sep'}, | ||||
|             { | ||||
|                 'title': "App Settings", | ||||
|                 'route': 'appsettings', | ||||
|                 'perm': 'settings.list', | ||||
|             }, | ||||
|             { | ||||
|                 'title': "Email Settings", | ||||
|                 'route': 'emailprofiles', | ||||
|                 'perm': 'emailprofiles.list', | ||||
|             }, | ||||
|             { | ||||
|                 'title': "Raw Settings", | ||||
|                 'route': 'settings', | ||||
|                 'perm': 'settings.list', | ||||
|             }, | ||||
|             {'type': 'sep'}, | ||||
|             { | ||||
|                 'title': "Tables", | ||||
|                 'route': 'tables', | ||||
|                 'perm': 'tables.list', | ||||
|             }, | ||||
|             { | ||||
|                 'title': "Messkit Upgrades", | ||||
|                 'route': 'upgrades', | ||||
|                 'perm': 'upgrades.list', | ||||
|             }, | ||||
|         ], | ||||
|     } | ||||
|         people_menu = { | ||||
|             'title': "People", | ||||
|             'type': 'menu', | ||||
|             'items': [ | ||||
|                 { | ||||
|                     'title': "All People", | ||||
|                     'route': 'people', | ||||
|                     'perm': 'people.list', | ||||
|                 }, | ||||
|             ], | ||||
|         } | ||||
| 
 | ||||
|     menus = [ | ||||
|         people_menu, | ||||
|         reports_menu, | ||||
|         admin_menu, | ||||
|     ] | ||||
|         reports_menu = self.make_reports_menu(request, include_poser=True) | ||||
| 
 | ||||
|     return menus | ||||
|         admin_menu = self.make_admin_menu(request, include_stores=False) | ||||
| 
 | ||||
|         menus = [ | ||||
|             people_menu, | ||||
|             reports_menu, | ||||
|             admin_menu, | ||||
|         ] | ||||
| 
 | ||||
|         return menus | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| ###################################################################### | ||||
| # | ||||
| #  Messkit -- Generic-ish Data Utility App | ||||
| #  Copyright © 2022 Lance Edgar | ||||
| #  Copyright © 2022-2023 Lance Edgar | ||||
| # | ||||
| #  This file is part of Messkit. | ||||
| # | ||||
|  | @ -30,8 +30,6 @@ from tailbone.util import include_configured_views | |||
| def includeme(config): | ||||
| 
 | ||||
|     config.include('tailbone.views.essentials') | ||||
| 
 | ||||
|     config.include('tailbone.views.poser') | ||||
|     config.include('tailbone.views.reports') | ||||
| 
 | ||||
|     include_configured_views(config) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lance Edgar
						Lance Edgar