diff --git a/.gitignore b/.gitignore index 2593080..da46463 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,3 @@ -*~ -*.pyc -dist/ rattail_tutorial.egg-info/ docs/_build/ .tox/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b57c8f..f908fda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,24 +5,6 @@ All notable changes to rattail-tutorial will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project (probably doesn't) adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). -## v0.3.1 (2024-07-01) - -### Fix - -- remove legacy command definitions - -## v0.3.0 (2024-07-01) - -### Feat - -- migrate all commands to use `typer` framework - -## v0.2.0 (2024-07-01) - -### Feat - -- switch from setup.cfg to pyproject.toml + hatchling - ## [0.1.0] - 2019-08-15 ### Changed - Initial version, with very basic (mostly generated) app. diff --git a/README.md b/README.rst similarity index 59% rename from README.md rename to README.rst index d8b38c1..1d15628 100644 --- a/README.md +++ b/README.rst @@ -1,9 +1,13 @@ +.. -*- mode: rst -*- -# rattail-tutorial +rattail-tutorial +================ This project is intended for use as a "tutorial" for Rattail app development. It contains documentation for the tutorial itself, but also contains code for the tutorial app, which users may run locally for testing. -See the [Rattail website](https://rattailproject.org/) for more info. +See the `Rattail website`_ for more info. + +.. _`Rattail website`: https://rattailproject.org/ diff --git a/Vagrantfile b/Vagrantfile index 5da7689..0c359c8 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -5,7 +5,4 @@ Vagrant.configure("2") do |config| # target machine runs Debian 10 "buster" config.vm.box = "debian/buster64" - # rattail-tutorial web app - config.vm.network "forwarded_port", guest: 9080, host: 9080 - end diff --git a/docs/conf.py b/docs/conf.py index eb80bf5..50aaca2 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -17,14 +17,12 @@ # -- Project information ----------------------------------------------------- -from importlib.metadata import version as get_version - project = 'rattail-tutorial' -copyright = '2019-2024, Lance Edgar' +copyright = '2019, Lance Edgar' author = 'Lance Edgar' # The full version, including alpha/beta/rc tags -release = get_version('rattail-tutorial') +release = '0.1' # -- General configuration --------------------------------------------------- @@ -53,7 +51,7 @@ todo_include_todos = True # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'furo' +html_theme = 'alabaster' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, diff --git a/docs/create-project.rst b/docs/create-project.rst index 9cb84ec..4c6932a 100644 --- a/docs/create-project.rst +++ b/docs/create-project.rst @@ -125,7 +125,7 @@ rattail-tutorial app instead, you should do this:: mkdir -p ~/src cd ~/src - git clone https://forgejo.wuttaproject.org/rattail/rattail-tutorial.git + git clone https://rattailproject.org/git/rattail-tutorial.git pip install -e rattail-tutorial Creating the Project diff --git a/docs/customize/disable-web-view.rst b/docs/customize/disable-web-view.rst deleted file mode 100644 index 8e1cc0e..0000000 --- a/docs/customize/disable-web-view.rst +++ /dev/null @@ -1,89 +0,0 @@ - -Hide / Disable Unwanted Web Views -================================= - -The first thing we'll want to do is take stock of the views currently exposed -by the web app, and either hide or outright "remove" any we don't want (yet). - -There are sort of 3 different aspects to whether or not a particular web view -is "available" for a given user: - -* is the view even defined? -* does user have permission to access the view? -* is there a menu (or other) link to the view? - -Removing a (Master) View ------------------------- - -There are a few "core" web views which will "always" be defined, but the vast -majority are really optional. The so-called "master" web views, each of which -basically corresponds to a particular table in the DB, are (almost?) entirely -optional. For instance if your organization needs to track customers but not -products, within your Poser app, then you might go so far as to "remove" the -product views from your app. - -If you do this, then e.g. navigating to http://localhost:9080/products/ (or -whatever your URL is) would result in a 404 not found error regardless of user -permissions, i.e. even if you "become root". However by default (using code -generated via scaffold) the product views *are* enabled, so this URL *would* -work. - -Whether or not a given view(s) is "defined" will depend on whether or not the -module containing this view(s) has been "included" by the Pyramid (web app) -Configurator object. In other words we're leveraging this "include" concept -from `Pyramid`_ in order to control which views are brought into the running -app. - -.. _Pyramid: https://trypyramid.com/ - -In practice what that means is usually just that you must curate the list of -views which are included, within your own project. This config thing works -recursively, but we try to keep the primary list within a conventional place. -In our (tutorial's) case this file is at -``~/src/rattail-tutorial/rattail_tutorial/web/views/__init__.py`` and by -default (freshly generated via scaffold) it looks something like this:: - - def includeme(config): - - # core views - config.include('rattail_tutorial.web.views.common') - config.include('tailbone.views.auth') - config.include('tailbone.views.tables') - config.include('tailbone.views.upgrades') - config.include('tailbone.views.progress') - - # main table views - config.include('tailbone.views.brands') - config.include('tailbone.views.customers') - config.include('tailbone.views.customergroups') - config.include('tailbone.views.datasync') - config.include('tailbone.views.departments') - config.include('tailbone.views.email') - config.include('tailbone.views.employees') - config.include('tailbone.views.messages') - config.include('tailbone.views.people') - config.include('tailbone.views.products') - config.include('tailbone.views.reportcodes') - config.include('tailbone.views.roles') - config.include('tailbone.views.settings') - config.include('tailbone.views.shifts') - config.include('tailbone.views.stores') - config.include('tailbone.views.subdepartments') - config.include('tailbone.views.users') - config.include('tailbone.views.vendors') - - # batch views - config.include('tailbone.views.handheld') - config.include('tailbone.views.inventory') - -In our case the only thing we'll remove for now is the "shifts" entry, i.e. we -wish to remove the line that says:: - - config.include('tailbone.views.shifts') - -That's because these views have to do with staff scheduling and time clock -stuff, which (at least for now) we won't concern ourselves with. - -Note that the underlying *tables* which might contain such data, are left in -place within our database. We're just declaring that we do not need our web -app to support master views for interacting with those tables. diff --git a/docs/customize/index.rst b/docs/customize/index.rst deleted file mode 100644 index 8986d22..0000000 --- a/docs/customize/index.rst +++ /dev/null @@ -1,22 +0,0 @@ - -Customizing the App! -==================== - -Now that you've made it through the "setup" gauntlet, it's finally time for -some fun stuff. - -As we're building this tutorial, at this point our project is *basically* the -same as any other "Poser" project, as generated via scaffold. But as we keep -going, our project will become more and more customized for the purposes of the -tutorial. - -So if you have just created a new project, some of this might make more sense -to you, vs. if you're running the rattail-tutorial project itself, many things -described in this section will have already been done (and then some) to the -code base, so you should keep that in mind when reading. - - -.. toctree:: - :maxdepth: 2 - - disable-web-view diff --git a/docs/index.rst b/docs/index.rst index a434455..687f895 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -55,10 +55,6 @@ Table of Contents create-project start-docs configure - pkg-release - make-db - run-webapp - customize/index Indices and tables diff --git a/docs/make-db.rst b/docs/make-db.rst deleted file mode 100644 index b4d437e..0000000 --- a/docs/make-db.rst +++ /dev/null @@ -1,87 +0,0 @@ - -.. highlight:: sh - -Establish Main App Database -=========================== - -Now that you have a hang of how to use the Rattail-style command line -(somewhat), let's move on to the database. - -The main reason to wait until now to add a DB to the mix, was simply to show -that the "core" of Rattail does not need a DB. However in practice there *are* -definitely some commands which Rattail comes with out of the box, and which -also would require one or even multiple databases to be present. - - -Create User for PostgreSQL --------------------------- - -Before we make our database, let's first establish a user account within -Postgres, which we will designate as the "owner" of our database(s). - -It is convention within Rattail, to create a PG user named "rattail" for this -purpose. You are free to use another name if you prefer:: - - sudo -u postgres createuser --no-createdb --no-createrole --no-superuser rattail - -You also should declare a password for the user:: - - sudo -u postgres psql -c "alter user rattail password 'newpassword'" - - -Create Database ---------------- - -Now that we know who to use as the "owner" we will create a new Postgres -database:: - - sudo -u postgres createdb --owner rattail rattut - -Of course we named our database "rattut" here only because we're assuming this -tutorial project is the app, but your name may be different. - -At this point you should update your ``app/rattail.conf`` file to reflect your -chosen database name and user credentials: - -.. code-block:: ini - - [rattail.db] - default.url = postgresql://rattail:newpassword@localhost/rattut - - -Install DB Schema ------------------ - -So you have a DB but it’s empty; you can confirm that with:: - - sudo -u postgres psql -c '\d' rattut - -But we'll fix that now. Schema is managed entirely via Alembic "version" -scripts, so to install the schema we merely run all the scripts:: - - cdvirtualenv - bin/alembic -c app/rattail.conf upgrade heads - -(Note that you must use ``rattail.conf`` for that; ``quiet.conf`` won't work.) - -If you check the DB again you should see a good amount of tables. - - -.. _make-user: - -Create Admin User in DB ------------------------ - -We include this here not so much because you *need* an admin user in your DB at -this point (although you will for the web app), but rather just to confirm that -everything is setup correctly thus far. - -You currently should have no users in your DB:: - - sudo -u postgres psql -c 'select * from "user"' rattut - -Okay then let's make an admin user for you:: - - bin/rattail -c app/quiet.conf make-user --admin myusername - -Now if you query the ``user`` table again you should see your new account. diff --git a/docs/pkg-release.rst b/docs/pkg-release.rst deleted file mode 100644 index b65a054..0000000 --- a/docs/pkg-release.rst +++ /dev/null @@ -1,118 +0,0 @@ - -.. highlight:: sh - -Build a Release for the Project -=============================== - -Even though our app does very little at this stage, we wish to go ahead and -"release" our first version for it. - -.. note:: - Whether or not you actually need to build releases for your project, may - depend on your use case. For instance if you have reason to run the app(s) - directly from source (i.e. git HEAD) then you may have no use for a built - package. - - -Project Versioning ------------------- - -The project's current version "number" is kept in only one place really, in our -case ``~/src/rattail-tutorial/rattail_tutorial/_version.py``. Other files are -configured to read the current project version from there. - -The initial version for a new project will generally be '0.1.0' and it's -assumed that subsequent versions will be '0.1.1' then '0.1.2' etc. until you've -decided that it's time to do a '0.2.0' release, and the cycle begins again. - -You can be as aggressive or conservative as you like when it comes to -incrementing the more "major" parts of the version number, e.g. you can -increment conservatively to where you've just released say, '0.1.427' before you -finally go to '0.2.0'. The only real "requirement" (assumption) here is that -you will build a new version release *every time* you update the production -environment(s). Sometimes that may mean multiple releases in a given day, -e.g. if the first one ships with a bug and you have to push a release to fix. - - -Install Invoke --------------- - -While you can most certainly go about the build/release task in various ways, -the convention within Rattail-land is to use `Invoke`_. - -.. _Invoke: https://www.pyinvoke.org/ - -So next we'll install that to your virtualenv:: - - pip install invoke - -You may also want to declare this within your project's dependencies (in -``setup.py``), but that's up to you. - - -Create Tasks File ------------------ - -The ``invoke`` command will invoke tasks which we have defined in a tasks file. -(Duh!) - -We will now create a file at ``~/src/rattail-tutorial/tasks.py`` and in it -place some minimal contents: - -.. code-block:: python3 - - # -*- coding: utf-8; -*- - """ - Tasks for 'rattail-tutorial' project - """ - - from invoke import task - - # this is needed to read current `__version__` value - #import os - #here = os.path.abspath(os.path.dirname(__file__)) - #exec(open(os.path.join(here, 'rattail_tutorial', '_version.py')).read()) - - - @task - def release(c): - """ - Release a new version of `rattail-tutorial`. - """ - # clear out previous package info - c.run('rm -rf rattail_tutorial.egg-info') - - # build fresh package! - c.run('python setup.py sdist --formats=gztar') - - # enable this if you intend to publish package to PyPI - #c.run('twine upload dist/rattail-tutorial-{}.tar.gz'.format(__version__)) - -If you're creating your own project then you can use the above as a starting -point for your own file. Instead of using ``twine`` to upload the package to -`PyPI`_, you may need to push to some private package repository which you -control. - -.. _PyPI: https://pypi.org/ - - -Run Release Task ----------------- - -As you can see above, ``release`` is the one and only task we have defined so -far. In most cases that will be the only task you ever define for the project, -but YMMV. - -At any rate it's all we need for now, so let's run it:: - - cd ~/src/rattail-tutorial - invoke release - -If you're feeling lazy you can even shorten that second one to:: - - inv release - -This will build a new "release" which may then be found within e.g. the -``~/src/rattail-tutorial/dist/`` folder. Depending on the specifics of your -tasks file, this release may also be uploaded to some (public or private) -package index. diff --git a/docs/run-webapp.rst b/docs/run-webapp.rst deleted file mode 100644 index 42c0f9b..0000000 --- a/docs/run-webapp.rst +++ /dev/null @@ -1,77 +0,0 @@ - -.. highlight:: sh - -Run the Web App -=============== - -At this point we assume you already have a project installed to your -virtualenv, and have done basic configuration as well as established your app -database. - - -Make/Edit Config ----------------- - -If you've been following along with this tutorial you may have already done -this step, but in any case we'll revisit now. - -If you do *not* yet have a file at e.g. ``/srv/envs/rattut/app/web.conf`` then -you should now run:: - - cdvirtualenv app - rattail make-config -T web - -Then you must edit the generated file, looking for TODO notes and such, and -generally tweaking things to your liking. - - -Start the Web App ------------------ - -The web app is effectively a daemon, in that it's meant to be a long-running -process which continues to listen for and respond to incoming requests. - -In production, this may be wired up in various ways, but for now we're only -concerned with development, where we'll be starting the web app "server" from -command line:: - - cdvirtualenv - bin/pserve --reload file+ini:app/web.conf - -Note that this command will "block" - meaning control will not immediately fall -back to your shell prompt. You may use Ctrl+C whenever you like, to kill the -web app. - - -Browse the Web App ------------------- - -This will only work when the above ``pserve`` command is running, but assuming -it is currently, you can access the web app at http://localhost:9080/ - -Note that the default ``web.conf`` specifies 9080 as the port on which the web -app will listen. You can modify this as needed, but if you do, and are also -using Vagrant, you may also need to modify your ``Vagrantfile`` (and do a -``vagrant reload``). - - -Login to Web App ----------------- - -If you've been following along with the tutorial then you probably have already -created an admin account for yourself. But in case you haven't, please see -:ref:`make-user`. - -Once that's set then you should be able to login to the web app with those same -credentials. - -The very first thing you see is likely "not much" - most of the menu will be -hidden to you, since by default you do not have sufficient permissions to -access the features they represent. - -However you are an "admin" user - which really just means your user account -belongs to the special "Administrators" role. This role is special in that -anyone who belongs to it, is given an extra "Become Root" option in the menu. -This works similarly to the Linux "root" concept, in that if you become root, -you will be implicitly granted *all* permissions and nothing will be hidden -from you. This lasts until you "stop being root" or logout. diff --git a/docs/start-docs.rst b/docs/start-docs.rst index 1878a2a..4b937f7 100644 --- a/docs/start-docs.rst +++ b/docs/start-docs.rst @@ -1,8 +1,8 @@ .. highlight:: sh -Document Your Project -===================== +Documenting Your Project +======================== At this point we assume you already have created a new project, and established the Git repo for it etc. diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index f2c9f05..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,62 +0,0 @@ - -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" - - -[project] -name = "rattail-tutorial" -version = "0.3.1" -description = "Rattail Development Tutorial" -readme = "README.md" -authors = [{name = "Lance Edgar", email = "lance@edbob.org"}] -license = {text = "GNU GPL v3+"} -classifiers = [ - "Development Status :: 3 - Alpha", - "Environment :: Console", - "Environment :: Web Environment", - "Framework :: Pyramid", - "Intended Audience :: Developers", - "Natural Language :: English", - "Operating System :: POSIX :: Linux", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Topic :: Office/Business", -] -dependencies = [ - "furo", - "invoke", - "psycopg2", - "rattail[db,bouncer]", - "Sphinx", - "Tailbone", - "tox", -] - - -[project.scripts] -rattail_tutorial = "rattail_tutorial.commands:rattail_tutorial_typer" - - -[project.entry-points."paste.app_factory"] -main = "rattail_tutorial.web.app:main" - - -[project.entry-points."rattail.config.extensions"] -rattail_tutorial = "rattail_tutorial.config:RattailTutorialConfig" - - -[project.entry-points."rattail.emails"] -rattail_tutorial = "rattail_tutorial.emails" - - -[project.urls] -Homepage = "https://rattailproject.org" -repository = "https://forgejo.wuttaproject.org/rattail/rattail-tutorial" -Changelog = "https://forgejo.wuttaproject.org/rattail/rattail-tutorial/src/branch/master/CHANGELOG.md" - - -[tool.commitizen] -version_provider = "pep621" -tag_format = "v$version" -update_changelog_on_bump = true diff --git a/rattail_tutorial/_version.py b/rattail_tutorial/_version.py index fcfc0bd..e41b669 100644 --- a/rattail_tutorial/_version.py +++ b/rattail_tutorial/_version.py @@ -1,6 +1,3 @@ # -*- coding: utf-8; -*- -from importlib.metadata import version - - -__version__ = version('rattail-tutorial') +__version__ = '0.1.0' diff --git a/rattail_tutorial/commands.py b/rattail_tutorial/commands.py index 87c50f9..78e2dd5 100644 --- a/rattail_tutorial/commands.py +++ b/rattail_tutorial/commands.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2024 Lance Edgar +# Copyright © 2010-2019 Lance Edgar # # This file is part of Rattail. # @@ -26,22 +26,36 @@ Rattail Tutorial commands import sys -import typer +from rattail import commands -from rattail.commands.typer import make_typer +from rattail_tutorial import __version__ -rattail_tutorial_typer = make_typer( - name='rattail_tutorial', - help="Rattail Tutorial (custom Rattail system)" -) +def main(*args): + """ + Main entry point for Rattail Tutorial command system + """ + args = list(args or sys.argv[1:]) + cmd = Command() + cmd.run(*args) -@rattail_tutorial_typer.command() -def hello( - ctx: typer.Context, -): +class Command(commands.Command): + """ + Main command for Rattail Tutorial + """ + name = 'rattail_tutorial' + version = __version__ + description = "Rattail Tutorial (custom Rattail system)" + long_description = '' + + +class HelloWorld(commands.Subcommand): """ The requisite 'hello world' example """ - sys.stdout.write("hello world!\n") + name = 'hello' + description = __doc__.strip() + + def run(self, args): + self.stdout.write("hello world!\n") diff --git a/rattail_tutorial/config.py b/rattail_tutorial/config.py index 5b54e1f..1415ea1 100644 --- a/rattail_tutorial/config.py +++ b/rattail_tutorial/config.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2024 Lance Edgar +# Copyright © 2010-2019 Lance Edgar # # This file is part of Rattail. # @@ -24,10 +24,10 @@ Custom config """ -from wuttjamaican.conf import WuttaConfigExtension +from rattail.config import ConfigExtension -class RattailTutorialConfig(WuttaConfigExtension): +class Rattail_tutorialConfig(ConfigExtension): """ Rattail config extension for Rattail Tutorial """ @@ -36,4 +36,5 @@ class RattailTutorialConfig(WuttaConfigExtension): def configure(self, config): # set some default config values - config.setdefault('tailbone.menus.handler', 'rattail_tutorial.web.menus:TutorialMenuHandler') + config.setdefault('rattail.mail', 'emails', 'rattail_tutorial.emails') + config.setdefault('tailbone', 'menus', 'rattail_tutorial.web.menus') diff --git a/rattail_tutorial/emails.py b/rattail_tutorial/emails.py index 4359049..1e82c6a 100644 --- a/rattail_tutorial/emails.py +++ b/rattail_tutorial/emails.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2024 Lance Edgar +# Copyright © 2010-2019 Lance Edgar # # This file is part of Rattail. # @@ -26,6 +26,9 @@ Custom email profiles from rattail.mail import Email +# bring in some common ones from rattail +from rattail.emails import datasync_error_watcher_get_changes, filemon_action_error + class rattail_import_sample_updates(Email): """ diff --git a/rattail_tutorial/web/menus.py b/rattail_tutorial/web/menus.py index 402ca8a..b9b6d40 100644 --- a/rattail_tutorial/web/menus.py +++ b/rattail_tutorial/web/menus.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2024 Lance Edgar +# Copyright © 2010-2019 Lance Edgar # # This file is part of Rattail. # @@ -24,139 +24,166 @@ Web Menus """ -from tailbone import menus as base +def simple_menus(request): + url = request.route_url -class TutorialMenuHandler(base.MenuHandler): - """ - Demo menu handler - """ - - def make_menus(self, request, **kwargs): - - products_menu = self.make_products_menu(request) - - vendors_menu = self.make_vendors_menu(request) - - company_menu = self.make_company_menu(request) - - batches_menu = self.make_batches_menu(request) - - admin_menu = self.make_admin_menu(request, - include_stores=False, - include_tenders=False) - - menus = [ - products_menu, - vendors_menu, - company_menu, - batches_menu, - admin_menu, - ] - - return menus - - def make_products_menu(self, request, **kwargs): - return { + menus = [ + { 'title': "Products", 'type': 'menu', 'items': [ { 'title': "Products", - 'route': 'products', + 'url': url('products'), 'perm': 'products.list', }, { 'title': "Brands", - 'route': 'brands', + 'url': url('brands'), 'perm': 'brands.list', }, { 'title': "Report Codes", - 'route': 'reportcodes', + 'url': url('reportcodes'), 'perm': 'reportcodes.list', }, ], - } - - def make_vendors_menu(self, request, **kwargs): - return { + }, + { 'title': "Vendors", 'type': 'menu', 'items': [ { 'title': "Vendors", - 'route': 'vendors', + 'url': url('vendors'), 'perm': 'vendors.list', }, {'type': 'sep'}, { 'title': "Catalogs", - 'route': 'vendorcatalogs', + 'url': url('vendorcatalogs'), 'perm': 'vendorcatalogs.list', }, { 'title': "Upload New Catalog", - 'route': 'vendorcatalogs.create', + 'url': url('vendorcatalogs.create'), 'perm': 'vendorcatalogs.create', }, ], - } - - def make_company_menu(self, request, **kwargs): - return { + }, + { 'title': "Company", 'type': 'menu', 'items': [ { 'title': "Stores", - 'route': 'stores', + 'url': url('stores'), 'perm': 'stores.list', }, { 'title': "Departments", - 'route': 'departments', + 'url': url('departments'), 'perm': 'departments.list', }, { 'title': "Subdepartments", - 'route': 'subdepartments', + 'url': url('subdepartments'), 'perm': 'subdepartments.list', }, {'type': 'sep'}, { 'title': "Employees", - 'route': 'employees', + 'url': url('employees'), 'perm': 'employees.list', }, {'type': 'sep'}, { 'title': "Customers", - 'route': 'customers', + 'url': url('customers'), 'perm': 'customers.list', }, { 'title': "Customer Groups", - 'route': 'customergroups', + 'url': url('customergroups'), 'perm': 'customergroups.list', }, ], - } - - def make_batches_menu(self, request, **kwargs): - return { + }, + { 'title': "Batches", 'type': 'menu', 'items': [ { 'title': "Handheld", - 'route': 'batch.handheld', + 'url': url('batch.handheld'), 'perm': 'batch.handheld.list', }, { 'title': "Inventory", - 'route': 'batch.inventory', + 'url': url('batch.inventory'), 'perm': 'batch.inventory.list', }, ], - } + }, + { + 'title': "Admin", + 'type': 'menu', + 'items': [ + { + 'title': "Users", + 'url': url('users'), + 'perm': 'users.list', + }, + { + 'title': "User Events", + 'url': url('userevents'), + 'perm': 'userevents.list', + }, + { + 'title': "Roles", + 'url': url('roles'), + 'perm': 'roles.list', + }, + {'type': 'sep'}, + { + 'title': "App Settings", + 'url': url('appsettings'), + 'perm': 'settings.list', + }, + { + 'title': "Email Settings", + 'url': url('emailprofiles'), + 'perm': 'emailprofiles.list', + }, + { + 'title': "Email Attempts", + 'url': url('email_attempts'), + 'perm': 'email_attempts.list', + }, + { + 'title': "Raw Settings", + 'url': url('settings'), + 'perm': 'settings.list', + }, + {'type': 'sep'}, + { + 'title': "DataSync Changes", + 'url': url('datasyncchanges'), + 'perm': 'datasync.list', + }, + { + 'title': "Tables", + 'url': url('tables'), + 'perm': 'tables.list', + }, + { + 'title': "Rattail Tutorial Upgrades", + 'url': url('upgrades'), + 'perm': 'upgrades.list', + }, + ], + }, + ] + + return menus diff --git a/rattail_tutorial/web/templates/home.mako b/rattail_tutorial/web/templates/home.mako new file mode 100644 index 0000000..51360f4 --- /dev/null +++ b/rattail_tutorial/web/templates/home.mako @@ -0,0 +1,14 @@ +## -*- coding: utf-8; mode: html; -*- +<%inherit file="tailbone:templates/home.mako" /> + +<%def name="title()">Home + + + +

Welcome to Rattail Tutorial

+ diff --git a/rattail_tutorial/web/templates/login.mako b/rattail_tutorial/web/templates/login.mako new file mode 100644 index 0000000..786e149 --- /dev/null +++ b/rattail_tutorial/web/templates/login.mako @@ -0,0 +1,18 @@ +## -*- coding: utf-8; mode: html; -*- +<%inherit file="tailbone:templates/login.mako" /> + +<%def name="extra_styles()"> + ${parent.extra_styles()} + + + +<%def name="logo()"> + ## ${h.image(request.static_url('ratbob.web:static/img/ratbob.jpg'), "Ratbob Logo", id='logo', width=500)} + ${h.image(request.static_url('tailbone:static/img/home_logo.png'), "Rattail Logo", id='logo')} + + +${parent.body()} diff --git a/rattail_tutorial/web/views/__init__.py b/rattail_tutorial/web/views/__init__.py index 74d7029..f56118a 100644 --- a/rattail_tutorial/web/views/__init__.py +++ b/rattail_tutorial/web/views/__init__.py @@ -48,6 +48,7 @@ def includeme(config): config.include('tailbone.views.reportcodes') config.include('tailbone.views.roles') config.include('tailbone.views.settings') + config.include('tailbone.views.shifts') config.include('tailbone.views.stores') config.include('tailbone.views.subdepartments') config.include('tailbone.views.users') diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..49d9d72 --- /dev/null +++ b/setup.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8; -*- +################################################################################ +# +# Rattail -- Retail Software Framework +# Copyright © 2010-2019 Lance Edgar +# +# This file is part of Rattail. +# +# Rattail is free software: you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. +# +# Rattail 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 General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# Rattail. If not, see . +# +################################################################################ +""" +Rattail Tutorial setup script +""" + +import os +from setuptools import setup, find_packages + + +here = os.path.abspath(os.path.dirname(__file__)) +exec(open(os.path.join(here, 'rattail_tutorial', '_version.py')).read()) +README = open(os.path.join(here, 'README.rst')).read() + + +requires = [ + # + # Version numbers within comments below have specific meanings. + # Basically the 'low' value is a "soft low," and 'high' a "soft high." + # In other words: + # + # If either a 'low' or 'high' value exists, the primary point to be + # made about the value is that it represents the most current (stable) + # version available for the package (assuming typical public access + # methods) whenever this project was started and/or documented. + # Therefore: + # + # If a 'low' version is present, you should know that attempts to use + # versions of the package significantly older than the 'low' version + # may not yield happy results. (A "hard" high limit may or may not be + # indicated by a true version requirement.) + # + # Similarly, if a 'high' version is present, and especially if this + # project has laid dormant for a while, you may need to refactor a bit + # when attempting to support a more recent version of the package. (A + # "hard" low limit should be indicated by a true version requirement + # when a 'high' version is present.) + # + # In any case, developers and other users are encouraged to play + # outside the lines with regard to these soft limits. If bugs are + # encountered then they should be filed as such. + # + # package # low high + + 'psycopg2', # 2.6.2 + 'rattail[auth,db,bouncer]', # 0.7.25 + 'Tailbone', # 0.5.29 + 'tox', # 3.13.2 +] + + +setup( + name = "rattail-tutorial", + version = __version__, + author = "Lance Edgar", + author_email = "lance@edbob.org", + url = "https://rattailproject.org", + license = "GNU GPL v3", + description = "Rattail Development Tutorial", + long_description = README, + + classifiers = [ + 'Private :: Do Not Upload', + 'Development Status :: 3 - Alpha', + 'Environment :: Console', + 'Environment :: Web Environment', + 'Framework :: Pyramid', + 'Intended Audience :: Developers', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2.7', + 'Topic :: Office/Business', + ], + + install_requires = requires, + packages = find_packages(), + include_package_data = True, + + entry_points = { + + 'rattail.config.extensions': [ + 'rattail_tutorial = rattail_tutorial.config:Rattail_tutorialConfig', + ], + + 'console_scripts': [ + 'rattail_tutorial = rattail_tutorial.commands:main', + ], + + 'rattail_tutorial.commands': [ + 'hello = rattail_tutorial.commands:HelloWorld', + ], + + 'paste.app_factory': [ + 'main = rattail_tutorial.web.app:main', + ], + }, +) diff --git a/tasks.py b/tasks.py deleted file mode 100644 index f493ceb..0000000 --- a/tasks.py +++ /dev/null @@ -1,38 +0,0 @@ -# -*- coding: utf-8; -*- -################################################################################ -# -# Rattail -- Retail Software Framework -# Copyright © 2010-2024 Lance Edgar -# -# This file is part of Rattail. -# -# Rattail is free software: you can redistribute it and/or modify it under the -# terms of the GNU General Public License as published by the Free Software -# Foundation, either version 3 of the License, or (at your option) any later -# version. -# -# Rattail 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 General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License along with -# Rattail. If not, see . -# -################################################################################ -""" -Tasks for 'rattail-tutorial' package -""" - -from invoke import task - - -@task -def release(c): - """ - Release a new version of `rattail-tutorial`. - """ - c.run('rm -rf rattail_tutorial.egg-info') - c.run('rm -rf dist') - c.run('python -m build --sdist') - c.run('twine upload dist/*')