APPS = $(shell find $(ROOT_DIR) -name 'models.py' | sed 's,/models.py$$,,; s:.*/::')
+# In order to help newcomers, this variable holds a full doc of the current Makefile.
+# Please keep it up to date with regard to new commands.
+#
+# Structure:
+# - Group commands in sections
+# - Align command descriptions
+
+define help
+Makefile command help
+
+Available targets are:
+
+Running:
+ run: Start a development server on http://127.0.0.1:8000/
+ shell: Open a development Python shell using the current database
+
+Database:
+ resetdb: Reinitialize the database schema
+
+Testing:
+ test: Run the test suite
+
+Misc:
+ clean: Cleanup all temporary files (*.pyc, ...)
+ doc: Generate the documentation
+ help: Display this help message
+endef
+
default: all
all:
+help:
+ @echo -n "" # Don't display extra lines.
+ $(info $(help))
+
+
+.PHONY: all default help
+
+
+# Running
+# =======
+
run:
$(MANAGE_PY) runserver
shell:
$(MANAGE_PY) shell
+
+.PHONY: run shell
+
+# Development
+# ===========
+
+
test:
$(MANAGE_PY) test $(APPS)
rm -f xnet/db.sqlite
$(MANAGE_PY) syncdb --noinput
+.PHONY: resetdb test
+
+# Misc
+# ====
+
clean:
find . "(" -name "*.pyc" -or -name "*.pyo" -or -name "*.mo" ")" -delete
find . -type d -empty -delete
$(MAKE) -C doc html
-.PHONY: default all run shell test resetdb doc
+.PHONY: clean doc
--- /dev/null
+Architecture
+============
+
+The plat/al project relies heavily on Django's notion of applications.
+
+
+Applications
+------------
+
+Each functional unit (events, news, groups, accounts, profiles, payments, ...)
+should live in its own Django app.
+
+Such apps should follow the following layout:
+
+- ``__init__.py``: Mandatory for Python, should be empty
+- ``models.py``: Required by Django, contains all models
+- ``admin.py``: A (properly designed) Admin for each model
+- ``factories.py``: The set of `factories <http://factoryboy.rtfd.org/>`_ related to the models
+- ``tests.py``: The set of tests for the app
+
+If the application contains views, it should include the following files:
+
+- ``forms.py``: Home of the forms used in the app (if any)
+- ``views.py``: All view definitions
+- ``urls.py``: URL map of the application, to be included in ``xnet.urls``
+- ``templates/my_app/base.html``: Base template for the application.
+ Can be simply:
+
+ .. code-block:: html
+
+ {% extends "base.html" %}
+
+- ``templates/my_app/foo.html``: app-specific templates. They should all inherit
+ from ``my_app/base.html``.
+
+
+External libraries
+------------------
+
+Whenever a functionality can be provided by an external, existing library,
+that library should be added to the dependencies (and not copied to our code).
+
+- If it's a "production" dependency, add it to ``requirements.txt``.
+- If the dependency is only useful for development / testing / ..., add it to ``dev_requirements.txt``
+- Until plat/al has reached production, avoid too specific version ranges;
+ use ``foo>=1.1.3`` if using a feature only available in v1.1.3,
+ and avoid ``foo=1.1.3`` that would prevent us from seeing new features of the lib.
+
+
+Internal libraries (utilities)
+------------------------------
+
+Utilities should be placed in the ``xnet/utils/`` folder, with one "app" per subject.
+For instance, time-related functions could be provided in ``xnet/utils/time`` while
+image-related tools would live in ``xnet/utils/image``.
+
+
+
--- /dev/null
+Style guide
+===========
+
+This document describes the main coding rules in use in the plat/al codebase.
+
+Python
+------
+
+Plat/al mostly follows the :pep:8 rules and `Django's coding style`_.
+
+.. _Django's coding style: https://docs.djangoproject.com/en/dev/internals/contributing/writing-code/coding-style/
+
+Mostly:
+
+ - Lines are limited to 120 characters
+ - Indent with 4 spaces
+
+Annotations
+"""""""""""
+
+- Use ``TODO`` and ``FIXME`` annotations with the name of the assignee::
+
+ # TODO(x2006barrois): make the spam more explicit
+ # FIXME(x2008gelineau): this may fry the eggs
+
+- Use ``XXX`` for things we can't improve, such as limitations in Python::
+
+ # XXX: OrderedDict does not exist before Python 2.7
+
+
+Imports
+"""""""
+
+**Do not use** ``import *``.
+
+When importing from the same package, use relative imports.
+Otherwise, use absolute imports:
+
+.. code-block:: python
+
+ # xnet/foo/bar.py
+
+ # Absolute import of xnet.blih
+ from xnet import blih
+
+ # Relative import of xnet.foo.baz
+ from . import baz
+
+
+Imports should be ordered from most general to most local:
+
+#. Standard lib imports
+#. Django imports
+#. Third party lib imports
+#. Plat/al imports
+#. Current app imports
+
+
+Exceptions
+""""""""""
+
+Exceptions are quite powerful, but should be used properly.
+
+Each module defining custom exceptions should define a base class for its
+exceptions; other exceptions from the module must then inherit from that base
+exception. This makes it much easier to catch module-specific exceptions:
+
+
+.. code-block:: python
+
+ # blah/foo.py
+
+ class FooError(Exception):
+ """Base class for exceptions from blah.foo."""
+
+ class SpecificException(FooError):
+ """A specific exception."""
+
+ def some_fun():
+ """Demo function for exception catching."""
+ try:
+ do_something()
+ except SpecificException as e:
+ handle_specific_exception(e)
+
+ # module bar.py
+
+ def other_fun():
+ try:
+ do_something()
+ except foo.FooError as e:
+ handle_generic_foo_exception(e)
+
+
+Only catch the errors that you expect. Let the other errors propagate. Do not catch an exception then raise another one, as this hides the true cause of the error.
+
+Avoid generic excepts, or worse, naked excepts:
+
+- ``except Exception:`` will catch import or syntax exceptions
+- ``except:`` and ``except BaseException:`` will catch all exceptions, including ``KeyboardInterrupt``, thus preventing ``^C``.
This is done to avoid duplicating code for main price options and part price options.
-Alternate proposed implementation
----------------------------------
+Alternate proposed implementation (1)
+-------------------------------------
Same thing as above except that price options are only for the main event.
That way the code is a bit less ugly.
-Alternate proposed implementation
----------------------------------
+Alternate proposed implementation (2)
+-------------------------------------
Have EventParts have a foreign key to the main event part. The "root" of the event becomes the main part.
Plat/al 2 is the second version of the plat/al (platform for alumni) developed by Polytechnique.org.
-It relies on Django.
+It relies on `the Django framework <http://www.djangoproject.com>`_.
-Contents:
+This documentation mostly focuses on developer setup, conventions, code architecture.
+
+Getting started
+---------------
+
+If you're new to the project, the following documents should help understanding and contributing:
+
+- :doc:`setup`: How to setup your development environment
+- :doc:`coding_rules`: Coding style in use in the project
+- :doc:`architecture`: General architecture and code layout
+- :doc:`tools`: Common tools used during development
+
+
+Design docs
+-----------
+
+Those documents describe the design and thoughts about various core parts of plat/al:
+
+- :doc:`events`: Managing events, registrations, prices
+
+
+Contents
+--------
.. toctree::
:maxdepth: 2
setup
+ coding_rules
+ architecture
+ tools
+
+ events
Indices and tables
make resetdb
+.. note:: The provided Makefile holds a few helpful commands.
+ Use ``make help`` to get a list of available commands.
+
+
You may now populate your database with some development data:
.. code-block:: sh
--- /dev/null
+Development tools
+=================
+
+Plat/al relies on a few tools and base libraries.
+
+Django
+------
+
+Our base framework, we're using the latest released version (currently 1.5.1).
+Feel free to browse its excellent documentation at https://docs.djangoproject.com/
+
+
+Bootstrap
+---------
+
+Our web layout relies on Twitter's Bootstrap framework.
+We use a minified version based on Bootstrap v2.2.2.
+
+The documentation is available at http://twitter.github.com/bootstrap/.
+
+
+factory_boy
+-----------
+
+For testing, we rely on `FactoryBoy <http://factoryboy.rtfd.org>`_.
+This library allows to define custom "factories" for each model,
+which ease populating the database (in ``xnet.datasets``) or writing tests:
+
+.. code-block:: python
+
+ class SomeTestCase(unittest.TestCase):
+ def test_disabled_account(self):
+ # Get a disabled account, don't bother filling any required field.
+ account = factories.AccountFactory(is_active=False, password='foo')
+
+ self.assertFalse(
+ auth.authenticate(account.username, 'foo'))