Coder Social home page Coder Social logo

mischback / django-calingen Goto Github PK

View Code? Open in Web Editor NEW
4.0 3.0 0.0 584 KB

Django application to manage and create analogous calendar inlays

License: MIT License

Makefile 4.43% Python 83.90% HTML 6.19% TeX 4.64% CSS 0.84%
django calender pluggable

django-calingen's Introduction

django-calingen

GitHub branch checks state Read the Docs (version) Coverage Status GitHub License

PyPI PyPI - Python Version PyPI - Django Version

Code style: black Code style: djlint CodeFactor Grade

django-calingen is a pluggable Django application to generate analogous, legacy, paper-based calendar inlays - thus calender inlay generator.

Installation and Setup

Installation and Setup of django-calingen is provided in the official documentation: Quickstart / Step by Step

Contributing

Contributions are always welcome, be it bugs, feature requests or actual code. See Contribution Guidelines to get you started.

django-calingen's People

Contributors

dependabot[bot] avatar mischback avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

django-calingen's Issues

External Event Providers as Stand Alone Django Apps

Is your feature request related to a problem? Please describe.
Layouts are implemented as stand-alone Django apps and included for a project in its INSTALLED_APPS setting. calingen is able to pick them up, because the layouts implement LayoutProvider.

External Event Providers on the other hand are basically included into a project by providing their respective dotted Python path in calingen.settings.CALINGEN_EXTERNAL_EVENT_PROVIDER.

This seems inconsistent!

Describe the solution you'd like
Basically apply the solution for layouts to external event providers.

Pros

  • one app-specific setting is removed
  • consistent API
    • then CompilerProvider should be considered aswell!
  • EventProvider implementations as full Django apps would allow more flexibility while developing external event providers, they could possibly include their own models, ...

Cons

  • higher effort to create an EventProvider implementation
    • as of now, every Python-capable developer could implement an event provider. If turned into Django apps, knowledge of Django is required
    • this could be mitigated by providing a sufficient template repository!

URL namespaces

Describe the bug
The app's URL configuration simply provides urls to make the app work. These urls are named, but not put into their own namespace, thus they may clash with other app's urls.

Expected behavior
All of the urls of calingen should be put into their own namespace (most likely calingen). All internal uses of the (named) urls must use the namespaced urls (this is applicable to calls of reverse(), reverse_lazy in Python code and url in templates).

Additional context
https://docs.djangoproject.com/en/4.0/topics/http/urls/#url-namespaces

``Event``'s ``unique_together`` constraint

Describe the bug
Two distinct profiles can not add identical events.

Environment

  • Python version: any
  • Django version: any
  • django-calingen version: 1.1

Expected behavior
Having two distinct profiles, it should be possible for both of them to add an event which uses the same title and date.

Additional context
Add any other context about the problem here.
The Event model defines a unique_together constraint for title and start. Probably just adding profile to the list of fields should already solve this.

GitHub Actions and tox

  • tox is run in combination with tox-gh-actions
  • ci-default.yml workflow does limit the testing matrix (regarding windows' Python versions)

The mentioned limitation can be implemented directly in tox.ini / pyproject.toml, using something like

[tox]
envlist = 
  py37-django{31,32}-{linux,macos}
  py38-django{31,32,40}-{linux,macos}
  py{39,310}-django{31,32,40}-{linux,macos,windows}

[gh-actions]
python =
  3.7: py37
  3.8: py38
  3.9: py39
  3.10: py310

[gh-actions:env]
PLATFORM =
  ubuntu-latest: linux
  macos-latest: macos
  windows-latest: windows

The above would make parts of ci-default.yml obsolete:

  testing:
    name: Run tests on ${{ matrix.os }} for ${{ matrix.python-version }}
    needs: linting
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest]
        python-version: ["3.7", "3.8", "3.9", "3.10"]
        exclude:
          # exclude Python 3.7 and 3.8 on Windows
          # The excluded Python versions are provided without JSON1 extension of
          # sqlite
          - os: windows-latest
            python-version: "3.7"
          - os: windows-latest
            python-version: "3.8"
    runs-on: ${{ matrix.os }}

(The whole exclude block could be removed!)

Pro

  • all logical constraints regarding testing are provided in tox's configuration and not in the CI-specific configuration.

Con

  • slightly increased complexity of tox.ini / pyproject.toml

``Event`` instances should support recurrence

Describe the solution you'd like
Event instances should support recurrence!

This will be a major change and probably break backwards compatibility!

As of now, the Event model does not really support recurrence. For the available EventCategories, a yearly recurrence is implicitly assumed and implemented in calingen.models.event.Event.resolve().

The desired implementation would support the full set of recurrence as provided by dateutil.rrule.rrule(), which is already used in calingen.contrib.holidays.germany.provider.

Implementation Idea

  • add a CharField to the Event model, to store the string representation of rrule objects
  • modify Event.resolve() to actually apply the rrule
  • let the frontend handle the creation of the rrule, i.e. by using https://github.com/jakubroztocil/rrule
  • get string representation of the rrule from the frontend and just store it (and hope for 100% compatiblity)
  • does this imply to provide real templates?
  • How can be verified, that the rrule parsing of an (externally provided) rrule string actually works correctly?!

Tagging of ``Event`` instances

Describe the solution you'd like

  • Event instances can have zero, one or more Tags associated with them.
  • Tags should be tied to the Profile and should be manageable through the profile's configuration view
  • Tags should be assignable while creating/updating Event instances
    • [OPTIONAL, highly desired] new Tags can be created while creating an Event
  • should be backwards-compatible, meaning that Tags are optional!
  • Tags should be included in EventListView
    • dedicated column
    • each rendered by including a dedicated template (possibility to provide styling?)
  • Tag-related views:
    • CRUD of Tags
    • list of events by Tag

Django >4.0 Form Rendering

Is your feature request related to a problem? Please describe.
Not really a problem, but a new Django feature: Django 4.0 introduces template-based form rendering. Basically this means, that you can specify template_name, template_name_label, template_name_p. template_name_ul and template_name_table on a Form class. If you're then using {{ form }} in a template, the corresponding template will be used to render the form.

Now, that is really a great feature, allowing so much flexibility while working with forms.

On the other hand, the app should support Django 3.1/3.2 as long as possible.

Describe the solution you'd like
calingen's Form instances should support the new form rendering system by specifying template_name. However, this should happen in a way that is backwards compatible with Django 3.1/3.2.

I think I have found a solution:

  • as of this writing, calingen's forms are already handled by a special form rendering template (templates/calingen/includes/form.html), which is included by the actual view templates, e.g. templates/calingen/event_update.html:
    {% include "calingen/includes/form.html" with form=form %}
    
  • by switching the include line to this:
    {% include form.template_name with form=form %}
    
    the app would rely on the template_name attribute of the form, which is really close to the 4.0 behaviour. Obviously this would need any Form instance to actually specify this template_name attribute (most likely this could be set to a generic implementation, the existing templates/calingen/includes/form.html might even be sufficient)
  • this implementation relies on the fact, that the form is passed to renderer as part of the context (see here!). It deviates from Django's default implementation in https://github.com/django/django/tree/main/django/forms/templates/django/forms (this implementation relies on the specific context attributes fields, hidden_fields and errors), but manual experimentation works out.
  • However, if calingen is deployed in a 4.0 project, the admin can safely override any templates to fully exploit the new template-based rendering of forms.

Additional context

CI requirements

As of now, the packages to actually run the CI (and development) environments are hardcoded or must be installed manually.

Idea is to provide dedicated requirements files, i.e for:

  • tox
  • ci-testing

Files that would require updates

  • .github/workflows/ci-default.yml
  • .github/workflows/ci-release.yml
  • .github/CONTRIBUTING.md [edit: not longer relevant!]
  • docs/source/developer/development_setup.rst [edit: not longer relevant!]

[edit]: The requirements are not really described in the documentation, so the docs did not receive updates! I don't feel like a description of the different requirements files is really required, it can easily be reverse-engineered by looking at pyproject.toml (tox section) and the CI workflows.

No link to ``ProfileDeleteView``

The ProfileDeleteView isn't linked anywhere.

It should - at least - be included in app_base.html to make it available / known for frontend designers. Even better would be somewhere on the user's ProfileView.

How to Provide project-specific Translations

Describe the bug
Not actually a bug, but follow up to #45 and related to #26

Environment

  • Linux (Debian Bullseye)
  • Python 3.9
  • Django 4.0

Expected behavior
How to get a message file (*.po) for the project to define custom translations?

This should be mentioned in the documentation (admin documentation section).

Additional context
Several SO questions on this topic, solutions don't seem to work out of the box... Needs further investigations.

Stop focussing on TeX

Describe the solution you'd like
While the app was originally developed with a certain workflow based around TeX in mind, that is a restriction that is not really required.

Original Idea:

 --------------       ----------------       ------------------       -----------
| User creates |     | LayoutProvider |     | CompilerProvider |     | PDF is    |
| and updates  | --> | generates TeX  | --> | compiles TeX     | --> | served to |
| Events       |     | source         |     | source to PDF    |     | user      |
 --------------       ----------------       ------------------       -----------

However, in calingen.interfaces.plugin_api.CompilerProvider, the only real requirement is to provide a valid (Django) HTTP response object.

Nothing prevents us from lifting the restrictions even more and allow layouts to provide any type of compiled output, that may be picked up by the compiler implementation.

This would allow for purely HTML-based layouts aswell. It could even be possible to support Markdown, reST or CSV outputs.

Implementation

  • Rename module calingen.view.tex
    • Rename contained classes aswell
  • Rename module calingen.forms.tex
    • Rename contained classes aswell
  • Add required target_source attribute to calingen.interfaces.plugin_api.LayoutProvider
    • actually named layout_type
  • add Copy'n'PasteCompiler
    • return the rendered layout source code in an HTML template (pre or textarea)
  • add DownloadCompiler
    • serve rendered layout source code as file download
  • add HtmlOrDownloadCompiler
    • Serve browser-servable content directly
    • Use (existing) file download logic for any other content
  • Enhance calingen.contrib.compilers.noop Remove calingen.contrib.compilers.noop
  • [OPTIONAL] Allow for more than one installed compiler (CompilerProvider)
    • django.conf.settings provide an AVAILABLE_COMPILER option (list of importable CompilerProvider implementations)
    • django.conf.settings provide a DEFAULT_COMPILER option (a single importable CompilerProvider implementation)
    • the proposed settings above were discarded in favor of CALINGEN_COMPILER
    • django.conf.settings provide a mapping, which LayoutProvider.target_source is routed to which compiler implementation
    • let CompilerView sort out, which CompilerProvider to use, depending on the above settings
  • #35 (this feature was moved to its own issue)

``coverage`` configuration

Revisit the coverage section in pyproject.toml and clean up the options.

  • activate parallel execution of coverage run in coverage's configuration section instead of using the --parallel switch in tox's environments (--parallel is not documented in the most recent version of coverage anyway)
  • include a coverage erase in tox's testing environment (needs trying!)

EventForm: Make ``time`` optional!

Describe the bug
When adding a new Event, the form shows a field for the time part of the datetime object. While the app already catches dummy values and modifies them to "00:00:00", the field may not be left empty.

Expected behavior
The field can simply be skipped (at least for ANNUAL_ANNIVERSARIES.

[performance] EventQuerySet should prefetch the User object

  • Every Event instance includes a reference to a User object (owner)
  • This results in additional database queries, if an Event instance is displayed/rendered
  • There is already a custom EventQuerySet in use
  • provide the owner by prefetching the User object

Event types must be defined in just one spot!

Describe the bug
As of now, the different types of events are provided as an inner class of the Event model. However, they should be accessible / usable by other compontents of the application, e.g. the EventProvider implementations in contrib.

Expected behavior
Have one central location for this, i.e. constants module, so that the event types can be accessed from anywhere without to much hassle. Have a single source of truth.

CopyPasteCompiler - autoescaping

Describe the bug
Using the CopyPasteCompiler with a layout implementation of type html does not provide the rendered source code of the template inside of the <pre> tag.

Expected behavior

  • HTML-based layouts have their special characters automatically escaped, e.g. < = &lt;, and can be copy/pasted from the actual page (without using the page's source)
  • non-HTML-based layouts can be copy/pasted from the actual page (without using the page's source)
  • the (existent) TeX-based layouts deactivate Django's autoescape, because Django's escaping of HTML does interfere with TeX rendering. How does this behave, if the (final render) of TeX templates is then run through Django's autoescape?

Calender vs. Calendar

Describe the bug
Calendar is the correct word!

Expected behavior
Refactor every single occurence of Calender.

Refactor ``contrib.holidays``

As of now, resolve() is implemented in a specific EventProvider implementation (calingen.contrib.holidays.germany.provider.GermanyFederal), but is actually pretty robust and reusable code.

Idea:
Move to calingen.contrib.holidays

  • does this have a side-effect, e.g. having an additional event provider that does actually not provide events?
  • any circular import issues?!

Update localization

Describe the bug
During #32 some localizable strings were added, but the *.po files were not updated!

Calingen's templatetags

Is your feature request related to a problem? Please describe.
Follow up to #28: As of now, the provided templatetag is focused on TeX-based layouts.

Describe the solution you'd like
Get rid of the TeX-focus, make the provided substitutions more general (by renaming constants and functions) and extendable (Markdown, rST?).

ProfileUpdateView: EventProvider can be empty

Describe the bug
With a fresh Profile the user is redirected to his ProfileUpdateView. If he just clicks update, an IntegrityError is raised on Profile._event_provider.

Expected behavior
A clear and concise description of what you expected to happen.

Additional context
Most probably, the ProfileForm does not provide a valid initial value for _event_provider.

Visualization of Compiler Mappings

Provide a view to visualize which layout will be rendered by which compiler.

Implementation Idea

  • add a Class Based View
    • Providing the context (this should be easy):
      • get a list of all available layouts: LayoutProvider.list_available_plugins()
      • get a list of all available compilers: CompilerProvider.list_available_plugins()
      • get the compiler configuration: settings.CALINGEN_COMPILER
    • Unused Compiler: available CompilerProvider implementation not listed in settings.CALINGEN_COMPILER
    • Layout Mappings: Which compiler is used to render which layout?
  • use admin decorators and base templates
  • provide means to make this View actually available:
    • provide a custom AdminSite in contrib (carefully describe the caveats of using this)
    • provide an app-specific setting to make this view available with an app-specific url (then it may just be template work to make the view available)

PluginField and its user presentation

Describe the bug
PluginField (calingen.forms.fields) basically just displays the provided choices and uses the values fetched from calingen.models.profile.Profile.event_provider of the Profile model to determine, which of the choices should be pre selected.

The getter of event_provider evaluates the available plugins and modifies its return value accordingly, appending deactivated plugins to "unavailable".

Expected behavior
Possible solutions:

  1. ignore this: when the form (containing this field) is saved, the corresponding entry is silently stored in the "unavailable" part of the JSON object. This is currently not visible to the user.

  2. inform the user: possibly Django's messaging framework could be used. This would be another (implicit) dependency, which might not be desirable.

Filter ``Event`` instances by ``Tag``

Is your feature request related to a problem? Please describe.
Follow up to #42!

Describe the solution you'd like
During layout rendering process, provide the possibility to filter the list of Events by Tags.

  • filter by none, one or many Tags
  • provide logical connectors, if more than one Tag is used for filtering:
    • AND (all of list)
    • OR (one of list)

Documentation

The documentation must provide at least the following topics:

  • Changelog (!!!)
  • user documentation, e.g. how to use the app
  • admin documentation, e.g. how to host the app
  • developer documentation
    • clean / enhance API documentation
      • contrib
        • compiler
        • layouts
        • holidays providers
      • forms
      • interfaces
      • models
      • templatetags
      • views
    • pick up .github/CONTRIBUTING.md
    • general description of app-internal processes
    • Git branching model
    • release checklist
    • plugin API (general)
    • EventProvider authors moved to #51
    • LayoutProvider authors moved to #51
    • CompilerProvider authors moved to #51

``success_url`` after adding an Event

As of now, after adding an Event, EventDetailView is shown.

Probably better - from the perspective of an actual user - would be the EventListView.

EventListView template should provide the link to add another Event

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.