--- a/.hgignore Thu Jun 08 14:46:34 2017 +0200
+++ b/.hgignore Thu Jun 08 17:57:57 2017 +0200
@@ -24,3 +24,11 @@
\.swo$
\.swp$
\.orig$
+
+^src/.env$
+^src/run/
+^src/dist/
+^src/.vscode/
+^src/MANIFEST.in
+^src/MANIFEST
+^src/irinotes.egg-info/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/.env.tmpl Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,37 @@
+# Base url for the application. default=''
+BASE_URL=
+
+# base url for static resources (ends with "/")
+# default : /static/
+STATIC_URL=/static/
+
+# The absolute path to the directory where collectstatic will collect static files for deployment. (https://docs.djangoproject.com/en/1.11/ref/settings/#std:setting-STATIC_ROOT)
+# default: <path to irinotes repository clone>/run/web/static
+STATIC_ROOT=
+
+# Absolute filesystem path to the directory that will hold user-uploaded files (https://docs.djangoproject.com/en/1.11/ref/settings/#media-root)
+# default: <path to irinotes repository clone>/run/web/media
+MEDIA_ROOT=
+
+# Secret key for the application. cf. https://docs.djangoproject.com/en/1.11/ref/settings/#secret-key
+SECRET_KEY=ARANDOMSECRETKEY
+
+# Debug the application. Default True
+DEBUG=<true|False>
+
+# Comma separated values of authorized host. cf. https://docs.djangoproject.com/en/1.11/ref/settings/#allowed-hosts
+# default: empty
+ALLOWED_HOSTS=127.0.0.1,localhost
+
+# 12factor inspired DATABASE_URL environment variable cf.https://github.com/kennethreitz/dj-database-url
+# examples: postgres://<user>:<password>@<host>:<port>/<db_name>
+# examples: sqlite:////full/path/to/your/database/file.sqlite
+# default: sqlite:///<path to irinotes repository clone>/run/db/db.sqlite3
+DATABASE_URL=sqlite:///<path to irinotes repository clone>/run/db/db.sqlite3
+
+# path for the log file
+# default: <path to irinotes repository clone>/run/log/log.txt
+LOG_FILE=
+
+# log level one of CRITICAL, ERROR, WARNING, INFO, DEBUG, NOTSET. Default: ERROR
+LOG_LEVEL=DEBUG
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/.pylintrc Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,425 @@
+[MASTER]
+
+# A comma-separated list of package or module names from where C extensions may
+# be loaded. Extensions are loading into the active Python interpreter and may
+# run arbitrary code
+extension-pkg-whitelist=
+
+# Add files or directories to the blacklist. They should be base names, not
+# paths.
+ignore=CVS
+
+# Add files or directories matching the regex patterns to the blacklist. The
+# regex matches against base names, not paths.
+ignore-patterns=
+
+# Python code to execute, usually for sys.path manipulation such as
+# pygtk.require().
+#init-hook=
+
+# Use multiple processes to speed up Pylint.
+jobs=1
+
+# List of plugins (as comma separated values of python modules names) to load,
+# usually to register additional checkers.
+load-plugins=
+
+# Pickle collected data for later comparisons.
+persistent=yes
+
+# Specify a configuration file.
+#rcfile=
+
+# Allow loading of arbitrary C extensions. Extensions are imported into the
+# active Python interpreter and may run arbitrary code.
+unsafe-load-any-extension=no
+
+
+[MESSAGES CONTROL]
+
+# Only show warnings with the listed confidence levels. Leave empty to show
+# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
+confidence=
+
+# Disable the message, report, category or checker with the given id(s). You
+# can either give multiple identifiers separated by comma (,) or put this
+# option multiple times (only on the command line, not in the configuration
+# file where it should appear only once).You can also use "--disable=all" to
+# disable everything first and then reenable specific checks. For example, if
+# you want to run only the similarities checker, you can use "--disable=all
+# --enable=similarities". If you want to run only the classes checker, but have
+# no Warning level messages displayed, use"--disable=all --enable=classes
+# --disable=W"
+disable=print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call
+
+# Enable the message, report, category or checker with the given id(s). You can
+# either give multiple identifier separated by comma (,) or put this option
+# multiple time (only on the command line, not in the configuration file where
+# it should appear only once). See also the "--disable" option for examples.
+enable=
+
+
+[REPORTS]
+
+# Python expression which should return a note less than 10 (10 is the highest
+# note). You have access to the variables errors warning, statement which
+# respectively contain the number of errors / warnings messages and the total
+# number of statements analyzed. This is used by the global evaluation report
+# (RP0004).
+evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
+
+# Template used to display messages. This is a python new-style format string
+# used to format the message information. See doc for all details
+#msg-template=
+
+# Set the output format. Available formats are text, parseable, colorized, json
+# and msvs (visual studio).You can also give a reporter class, eg
+# mypackage.mymodule.MyReporterClass.
+output-format=text
+
+# Tells whether to display a full report or only the messages
+reports=no
+
+# Activate the evaluation score.
+score=yes
+
+
+[REFACTORING]
+
+# Maximum number of nested blocks for function / method body
+max-nested-blocks=5
+
+
+[BASIC]
+
+# Naming hint for argument names
+argument-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
+
+# Regular expression matching correct argument names
+argument-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
+
+# Naming hint for attribute names
+attr-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
+
+# Regular expression matching correct attribute names
+attr-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
+
+# Bad variable names which should always be refused, separated by a comma
+bad-names=foo,bar,baz,toto,tutu,tata
+
+# Naming hint for class attribute names
+class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
+
+# Regular expression matching correct class attribute names
+class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
+
+# Naming hint for class names
+class-name-hint=[A-Z_][a-zA-Z0-9]+$
+
+# Regular expression matching correct class names
+class-rgx=[A-Z_][a-zA-Z0-9]+$
+
+# Naming hint for constant names
+const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$
+
+# Regular expression matching correct constant names
+const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
+
+# Minimum line length for functions/classes that require docstrings, shorter
+# ones are exempt.
+docstring-min-length=30
+
+# Naming hint for function names
+function-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
+
+# Regular expression matching correct function names
+function-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
+
+# Good variable names which should always be accepted, separated by a comma
+good-names=i,j,k,ex,Run,_
+
+# Include a hint for the correct naming format with invalid-name
+include-naming-hint=no
+
+# Naming hint for inline iteration names
+inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$
+
+# Regular expression matching correct inline iteration names
+inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
+
+# Naming hint for method names
+method-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
+
+# Regular expression matching correct method names
+method-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
+
+# Naming hint for module names
+module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
+
+# Regular expression matching correct module names
+module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
+
+# Colon-delimited sets of names that determine each other's naming style when
+# the name regexes allow several styles.
+name-group=
+
+# Regular expression which should only match function or class names that do
+# not require a docstring.
+no-docstring-rgx=^_
+
+# List of decorators that produce properties, such as abc.abstractproperty. Add
+# to this list to register other decorators that produce valid properties.
+property-classes=abc.abstractproperty
+
+# Naming hint for variable names
+variable-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
+
+# Regular expression matching correct variable names
+variable-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
+
+
+[FORMAT]
+
+# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
+expected-line-ending-format=
+
+# Regexp for a line that is allowed to be longer than the limit.
+ignore-long-lines=^\s*(# )?<?https?://\S+>?$
+
+# Number of spaces of indent required inside a hanging or continued line.
+indent-after-paren=4
+
+# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
+# tab).
+indent-string=' '
+
+# Maximum number of characters on a single line.
+max-line-length=100
+
+# Maximum number of lines in a module
+max-module-lines=1000
+
+# List of optional constructs for which whitespace checking is disabled. `dict-
+# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
+# `trailing-comma` allows a space between comma and closing bracket: (a, ).
+# `empty-line` allows space-only lines.
+no-space-check=trailing-comma,dict-separator
+
+# Allow the body of a class to be on the same line as the declaration if body
+# contains single statement.
+single-line-class-stmt=no
+
+# Allow the body of an if to be on the same line as the test if there is no
+# else.
+single-line-if-stmt=no
+
+
+[LOGGING]
+
+# Logging modules to check that the string format arguments are in logging
+# function parameter format
+logging-modules=logging
+
+
+[MISCELLANEOUS]
+
+# List of note tags to take in consideration, separated by a comma.
+notes=FIXME,XXX,TODO
+
+
+[SIMILARITIES]
+
+# Ignore comments when computing similarities.
+ignore-comments=yes
+
+# Ignore docstrings when computing similarities.
+ignore-docstrings=yes
+
+# Ignore imports when computing similarities.
+ignore-imports=no
+
+# Minimum lines number of a similarity.
+min-similarity-lines=4
+
+
+[SPELLING]
+
+# Spelling dictionary name. Available dictionaries: none. To make it working
+# install python-enchant package.
+spelling-dict=
+
+# List of comma separated words that should not be checked.
+spelling-ignore-words=
+
+# A path to a file that contains private dictionary; one word per line.
+spelling-private-dict-file=
+
+# Tells whether to store unknown words to indicated private dictionary in
+# --spelling-private-dict-file option instead of raising a message.
+spelling-store-unknown-words=no
+
+
+[TYPECHECK]
+
+# List of decorators that produce context managers, such as
+# contextlib.contextmanager. Add to this list to register other decorators that
+# produce valid context managers.
+contextmanager-decorators=contextlib.contextmanager
+
+# List of members which are set dynamically and missed by pylint inference
+# system, and so shouldn't trigger E1101 when accessed. Python regular
+# expressions are accepted.
+generated-members=
+
+# Tells whether missing members accessed in mixin class should be ignored. A
+# mixin class is detected if its name ends with "mixin" (case insensitive).
+ignore-mixin-members=yes
+
+# This flag controls whether pylint should warn about no-member and similar
+# checks whenever an opaque object is returned when inferring. The inference
+# can return multiple potential results while evaluating a Python object, but
+# some branches might not be evaluated, which results in partial inference. In
+# that case, it might be useful to still emit no-member and other checks for
+# the rest of the inferred objects.
+ignore-on-opaque-inference=yes
+
+# List of class names for which member attributes should not be checked (useful
+# for classes with dynamically set attributes). This supports the use of
+# qualified names.
+ignored-classes=optparse.Values,thread._local,_thread._local
+
+# List of module names for which member attributes should not be checked
+# (useful for modules/projects where namespaces are manipulated during runtime
+# and thus existing member attributes cannot be deduced by static analysis. It
+# supports qualified module names, as well as Unix pattern matching.
+ignored-modules=
+
+# Show a hint with possible names when a member name was not found. The aspect
+# of finding the hint is based on edit distance.
+missing-member-hint=yes
+
+# The minimum edit distance a name should have in order to be considered a
+# similar match for a missing member name.
+missing-member-hint-distance=1
+
+# The total number of similar names that should be taken in consideration when
+# showing a hint for a missing member.
+missing-member-max-choices=1
+
+
+[VARIABLES]
+
+# List of additional names supposed to be defined in builtins. Remember that
+# you should avoid to define new builtins when possible.
+additional-builtins=
+
+# Tells whether unused global variables should be treated as a violation.
+allow-global-unused-variables=yes
+
+# List of strings which can identify a callback function by name. A callback
+# name must start or end with one of those strings.
+callbacks=cb_,_cb
+
+# A regular expression matching the name of dummy variables (i.e. expectedly
+# not used).
+dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
+
+# Argument names that match this expression will be ignored. Default to name
+# with leading underscore
+ignored-argument-names=_.*|^ignored_|^unused_
+
+# Tells whether we should check for unused import in __init__ files.
+init-import=no
+
+# List of qualified module names which can have objects that can redefine
+# builtins.
+redefining-builtins-modules=six.moves,future.builtins
+
+
+[CLASSES]
+
+# List of method names used to declare (i.e. assign) instance attributes.
+defining-attr-methods=__init__,__new__,setUp
+
+# List of member names, which should be excluded from the protected access
+# warning.
+exclude-protected=_asdict,_fields,_replace,_source,_make
+
+# List of valid names for the first argument in a class method.
+valid-classmethod-first-arg=cls
+
+# List of valid names for the first argument in a metaclass class method.
+valid-metaclass-classmethod-first-arg=mcs
+
+
+[DESIGN]
+
+# Maximum number of arguments for function / method
+max-args=5
+
+# Maximum number of attributes for a class (see R0902).
+max-attributes=7
+
+# Maximum number of boolean expressions in a if statement
+max-bool-expr=5
+
+# Maximum number of branch for function / method body
+max-branches=12
+
+# Maximum number of locals for function / method body
+max-locals=15
+
+# Maximum number of parents for a class (see R0901).
+max-parents=7
+
+# Maximum number of public methods for a class (see R0904).
+max-public-methods=20
+
+# Maximum number of return / yield for function / method body
+max-returns=6
+
+# Maximum number of statements in function / method body
+max-statements=50
+
+# Minimum number of public methods for a class (see R0903).
+min-public-methods=2
+
+
+[IMPORTS]
+
+# Allow wildcard imports from modules that define __all__.
+allow-wildcard-with-all=no
+
+# Analyse import fallback blocks. This can be used to support both Python 2 and
+# 3 compatible code, which means that the block might have code that exists
+# only in one or another interpreter, leading to false positives when analysed.
+analyse-fallback-blocks=no
+
+# Deprecated modules which should not be used, separated by a comma
+deprecated-modules=optparse,tkinter.tix
+
+# Create a graph of external dependencies in the given file (report RP0402 must
+# not be disabled)
+ext-import-graph=
+
+# Create a graph of every (i.e. internal and external) dependencies in the
+# given file (report RP0402 must not be disabled)
+import-graph=
+
+# Create a graph of internal dependencies in the given file (report RP0402 must
+# not be disabled)
+int-import-graph=
+
+# Force import order to recognize a module as part of the standard
+# compatibility libraries.
+known-standard-library=
+
+# Force import order to recognize a module as part of a third party library.
+known-third-party=enchant
+
+
+[EXCEPTIONS]
+
+# Exceptions that will emit a warning when being caught. Defaults to
+# "Exception"
+overgeneral-exceptions=Exception
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/LICENSE Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,520 @@
+Copyright (c) 2016, IRI (Institute d Recherche de d'Innovation)
+All rights reserved.
+
+
+
+
+CeCILL-B FREE SOFTWARE LICENSE AGREEMENT
+
+
+ Notice
+
+This Agreement is a Free Software license agreement that is the result
+of discussions between its authors in order to ensure compliance with
+the two main principles guiding its drafting:
+
+ * firstly, compliance with the principles governing the distribution
+ of Free Software: access to source code, broad rights granted to
+ users,
+ * secondly, the election of a governing law, French law, with which
+ it is conformant, both as regards the law of torts and
+ intellectual property law, and the protection that it offers to
+ both authors and holders of the economic rights over software.
+
+The authors of the CeCILL-B (for Ce[a] C[nrs] I[nria] L[ogiciel] L[ibre])
+license are:
+
+Commissariat à l'Energie Atomique - CEA, a public scientific, technical
+and industrial research establishment, having its principal place of
+business at 25 rue Leblanc, immeuble Le Ponant D, 75015 Paris, France.
+
+Centre National de la Recherche Scientifique - CNRS, a public scientific
+and technological establishment, having its principal place of business
+at 3 rue Michel-Ange, 75794 Paris cedex 16, France.
+
+Institut National de Recherche en Informatique et en Automatique -
+INRIA, a public scientific and technological establishment, having its
+principal place of business at Domaine de Voluceau, Rocquencourt, BP
+105, 78153 Le Chesnay cedex, France.
+
+
+ Preamble
+
+This Agreement is an open source software license intended to give users
+significant freedom to modify and redistribute the software licensed
+hereunder.
+
+The exercising of this freedom is conditional upon a strong obligation
+of giving credits for everybody that distributes a software
+incorporating a software ruled by the current license so as all
+contributions to be properly identified and acknowledged.
+
+In consideration of access to the source code and the rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty and the software's author, the holder of the
+economic rights, and the successive licensors only have limited liability.
+
+In this respect, the risks associated with loading, using, modifying
+and/or developing or reproducing the software by the user are brought to
+the user's attention, given its Free Software status, which may make it
+complicated to use, with the result that its use is reserved for
+developers and experienced professionals having in-depth computer
+knowledge. Users are therefore encouraged to load and test the
+suitability of the software as regards their requirements in conditions
+enabling the security of their systems and/or data to be ensured and,
+more generally, to use and operate it in the same conditions of
+security. This Agreement may be freely reproduced and published,
+provided it is not altered, and that no provisions are either added or
+removed herefrom.
+
+This Agreement may apply to any or all software for which the holder of
+the economic rights decides to submit the use thereof to its provisions.
+
+
+ Article 1 - DEFINITIONS
+
+For the purpose of this Agreement, when the following expressions
+commence with a capital letter, they shall have the following meaning:
+
+Agreement: means this license agreement, and its possible subsequent
+versions and annexes.
+
+Software: means the software in its Object Code and/or Source Code form
+and, where applicable, its documentation, "as is" when the Licensee
+accepts the Agreement.
+
+Initial Software: means the Software in its Source Code and possibly its
+Object Code form and, where applicable, its documentation, "as is" when
+it is first distributed under the terms and conditions of the Agreement.
+
+Modified Software: means the Software modified by at least one
+Contribution.
+
+Source Code: means all the Software's instructions and program lines to
+which access is required so as to modify the Software.
+
+Object Code: means the binary files originating from the compilation of
+the Source Code.
+
+Holder: means the holder(s) of the economic rights over the Initial
+Software.
+
+Licensee: means the Software user(s) having accepted the Agreement.
+
+Contributor: means a Licensee having made at least one Contribution.
+
+Licensor: means the Holder, or any other individual or legal entity, who
+distributes the Software under the Agreement.
+
+Contribution: means any or all modifications, corrections, translations,
+adaptations and/or new functions integrated into the Software by any or
+all Contributors, as well as any or all Internal Modules.
+
+Module: means a set of sources files including their documentation that
+enables supplementary functions or services in addition to those offered
+by the Software.
+
+External Module: means any or all Modules, not derived from the
+Software, so that this Module and the Software run in separate address
+spaces, with one calling the other when they are run.
+
+Internal Module: means any or all Module, connected to the Software so
+that they both execute in the same address space.
+
+Parties: mean both the Licensee and the Licensor.
+
+These expressions may be used both in singular and plural form.
+
+
+ Article 2 - PURPOSE
+
+The purpose of the Agreement is the grant by the Licensor to the
+Licensee of a non-exclusive, transferable and worldwide license for the
+Software as set forth in Article 5 hereinafter for the whole term of the
+protection granted by the rights over said Software.
+
+
+ Article 3 - ACCEPTANCE
+
+3.1 The Licensee shall be deemed as having accepted the terms and
+conditions of this Agreement upon the occurrence of the first of the
+following events:
+
+ * (i) loading the Software by any or all means, notably, by
+ downloading from a remote server, or by loading from a physical
+ medium;
+ * (ii) the first time the Licensee exercises any of the rights
+ granted hereunder.
+
+3.2 One copy of the Agreement, containing a notice relating to the
+characteristics of the Software, to the limited warranty, and to the
+fact that its use is restricted to experienced users has been provided
+to the Licensee prior to its acceptance as set forth in Article 3.1
+hereinabove, and the Licensee hereby acknowledges that it has read and
+understood it.
+
+
+ Article 4 - EFFECTIVE DATE AND TERM
+
+
+ 4.1 EFFECTIVE DATE
+
+The Agreement shall become effective on the date when it is accepted by
+the Licensee as set forth in Article 3.1.
+
+
+ 4.2 TERM
+
+The Agreement shall remain in force for the entire legal term of
+protection of the economic rights over the Software.
+
+
+ Article 5 - SCOPE OF RIGHTS GRANTED
+
+The Licensor hereby grants to the Licensee, who accepts, the following
+rights over the Software for any or all use, and for the term of the
+Agreement, on the basis of the terms and conditions set forth hereinafter.
+
+Besides, if the Licensor owns or comes to own one or more patents
+protecting all or part of the functions of the Software or of its
+components, the Licensor undertakes not to enforce the rights granted by
+these patents against successive Licensees using, exploiting or
+modifying the Software. If these patents are transferred, the Licensor
+undertakes to have the transferees subscribe to the obligations set
+forth in this paragraph.
+
+
+ 5.1 RIGHT OF USE
+
+The Licensee is authorized to use the Software, without any limitation
+as to its fields of application, with it being hereinafter specified
+that this comprises:
+
+ 1. permanent or temporary reproduction of all or part of the Software
+ by any or all means and in any or all form.
+
+ 2. loading, displaying, running, or storing the Software on any or
+ all medium.
+
+ 3. entitlement to observe, study or test its operation so as to
+ determine the ideas and principles behind any or all constituent
+ elements of said Software. This shall apply when the Licensee
+ carries out any or all loading, displaying, running, transmission
+ or storage operation as regards the Software, that it is entitled
+ to carry out hereunder.
+
+
+ 5.2 ENTITLEMENT TO MAKE CONTRIBUTIONS
+
+The right to make Contributions includes the right to translate, adapt,
+arrange, or make any or all modifications to the Software, and the right
+to reproduce the resulting software.
+
+The Licensee is authorized to make any or all Contributions to the
+Software provided that it includes an explicit notice that it is the
+author of said Contribution and indicates the date of the creation thereof.
+
+
+ 5.3 RIGHT OF DISTRIBUTION
+
+In particular, the right of distribution includes the right to publish,
+transmit and communicate the Software to the general public on any or
+all medium, and by any or all means, and the right to market, either in
+consideration of a fee, or free of charge, one or more copies of the
+Software by any means.
+
+The Licensee is further authorized to distribute copies of the modified
+or unmodified Software to third parties according to the terms and
+conditions set forth hereinafter.
+
+
+ 5.3.1 DISTRIBUTION OF SOFTWARE WITHOUT MODIFICATION
+
+The Licensee is authorized to distribute true copies of the Software in
+Source Code or Object Code form, provided that said distribution
+complies with all the provisions of the Agreement and is accompanied by:
+
+ 1. a copy of the Agreement,
+
+ 2. a notice relating to the limitation of both the Licensor's
+ warranty and liability as set forth in Articles 8 and 9,
+
+and that, in the event that only the Object Code of the Software is
+redistributed, the Licensee allows effective access to the full Source
+Code of the Software at a minimum during the entire period of its
+distribution of the Software, it being understood that the additional
+cost of acquiring the Source Code shall not exceed the cost of
+transferring the data.
+
+
+ 5.3.2 DISTRIBUTION OF MODIFIED SOFTWARE
+
+If the Licensee makes any Contribution to the Software, the resulting
+Modified Software may be distributed under a license agreement other
+than this Agreement subject to compliance with the provisions of Article
+5.3.4.
+
+
+ 5.3.3 DISTRIBUTION OF EXTERNAL MODULES
+
+When the Licensee has developed an External Module, the terms and
+conditions of this Agreement do not apply to said External Module, that
+may be distributed under a separate license agreement.
+
+
+ 5.3.4 CREDITS
+
+Any Licensee who may distribute a Modified Software hereby expressly
+agrees to:
+
+ 1. indicate in the related documentation that it is based on the
+ Software licensed hereunder, and reproduce the intellectual
+ property notice for the Software,
+
+ 2. ensure that written indications of the Software intended use,
+ intellectual property notice and license hereunder are included in
+ easily accessible format from the Modified Software interface,
+
+ 3. mention, on a freely accessible website describing the Modified
+ Software, at least throughout the distribution term thereof, that
+ it is based on the Software licensed hereunder, and reproduce the
+ Software intellectual property notice,
+
+ 4. where it is distributed to a third party that may distribute a
+ Modified Software without having to make its source code
+ available, make its best efforts to ensure that said third party
+ agrees to comply with the obligations set forth in this Article .
+
+If the Software, whether or not modified, is distributed with an
+External Module designed for use in connection with the Software, the
+Licensee shall submit said External Module to the foregoing obligations.
+
+
+ 5.3.5 COMPATIBILITY WITH THE CeCILL AND CeCILL-C LICENSES
+
+Where a Modified Software contains a Contribution subject to the CeCILL
+license, the provisions set forth in Article 5.3.4 shall be optional.
+
+A Modified Software may be distributed under the CeCILL-C license. In
+such a case the provisions set forth in Article 5.3.4 shall be optional.
+
+
+ Article 6 - INTELLECTUAL PROPERTY
+
+
+ 6.1 OVER THE INITIAL SOFTWARE
+
+The Holder owns the economic rights over the Initial Software. Any or
+all use of the Initial Software is subject to compliance with the terms
+and conditions under which the Holder has elected to distribute its work
+and no one shall be entitled to modify the terms and conditions for the
+distribution of said Initial Software.
+
+The Holder undertakes that the Initial Software will remain ruled at
+least by this Agreement, for the duration set forth in Article 4.2.
+
+
+ 6.2 OVER THE CONTRIBUTIONS
+
+The Licensee who develops a Contribution is the owner of the
+intellectual property rights over this Contribution as defined by
+applicable law.
+
+
+ 6.3 OVER THE EXTERNAL MODULES
+
+The Licensee who develops an External Module is the owner of the
+intellectual property rights over this External Module as defined by
+applicable law and is free to choose the type of agreement that shall
+govern its distribution.
+
+
+ 6.4 JOINT PROVISIONS
+
+The Licensee expressly undertakes:
+
+ 1. not to remove, or modify, in any manner, the intellectual property
+ notices attached to the Software;
+
+ 2. to reproduce said notices, in an identical manner, in the copies
+ of the Software modified or not.
+
+The Licensee undertakes not to directly or indirectly infringe the
+intellectual property rights of the Holder and/or Contributors on the
+Software and to take, where applicable, vis-à-vis its staff, any and all
+measures required to ensure respect of said intellectual property rights
+of the Holder and/or Contributors.
+
+
+ Article 7 - RELATED SERVICES
+
+7.1 Under no circumstances shall the Agreement oblige the Licensor to
+provide technical assistance or maintenance services for the Software.
+
+However, the Licensor is entitled to offer this type of services. The
+terms and conditions of such technical assistance, and/or such
+maintenance, shall be set forth in a separate instrument. Only the
+Licensor offering said maintenance and/or technical assistance services
+shall incur liability therefor.
+
+7.2 Similarly, any Licensor is entitled to offer to its licensees, under
+its sole responsibility, a warranty, that shall only be binding upon
+itself, for the redistribution of the Software and/or the Modified
+Software, under terms and conditions that it is free to decide. Said
+warranty, and the financial terms and conditions of its application,
+shall be subject of a separate instrument executed between the Licensor
+and the Licensee.
+
+
+ Article 8 - LIABILITY
+
+8.1 Subject to the provisions of Article 8.2, the Licensee shall be
+entitled to claim compensation for any direct loss it may have suffered
+from the Software as a result of a fault on the part of the relevant
+Licensor, subject to providing evidence thereof.
+
+8.2 The Licensor's liability is limited to the commitments made under
+this Agreement and shall not be incurred as a result of in particular:
+(i) loss due the Licensee's total or partial failure to fulfill its
+obligations, (ii) direct or consequential loss that is suffered by the
+Licensee due to the use or performance of the Software, and (iii) more
+generally, any consequential loss. In particular the Parties expressly
+agree that any or all pecuniary or business loss (i.e. loss of data,
+loss of profits, operating loss, loss of customers or orders,
+opportunity cost, any disturbance to business activities) or any or all
+legal proceedings instituted against the Licensee by a third party,
+shall constitute consequential loss and shall not provide entitlement to
+any or all compensation from the Licensor.
+
+
+ Article 9 - WARRANTY
+
+9.1 The Licensee acknowledges that the scientific and technical
+state-of-the-art when the Software was distributed did not enable all
+possible uses to be tested and verified, nor for the presence of
+possible defects to be detected. In this respect, the Licensee's
+attention has been drawn to the risks associated with loading, using,
+modifying and/or developing and reproducing the Software which are
+reserved for experienced users.
+
+The Licensee shall be responsible for verifying, by any or all means,
+the suitability of the product for its requirements, its good working
+order, and for ensuring that it shall not cause damage to either persons
+or properties.
+
+9.2 The Licensor hereby represents, in good faith, that it is entitled
+to grant all the rights over the Software (including in particular the
+rights set forth in Article 5).
+
+9.3 The Licensee acknowledges that the Software is supplied "as is" by
+the Licensor without any other express or tacit warranty, other than
+that provided for in Article 9.2 and, in particular, without any warranty
+as to its commercial value, its secured, safe, innovative or relevant
+nature.
+
+Specifically, the Licensor does not warrant that the Software is free
+from any error, that it will operate without interruption, that it will
+be compatible with the Licensee's own equipment and software
+configuration, nor that it will meet the Licensee's requirements.
+
+9.4 The Licensor does not either expressly or tacitly warrant that the
+Software does not infringe any third party intellectual property right
+relating to a patent, software or any other property right. Therefore,
+the Licensor disclaims any and all liability towards the Licensee
+arising out of any or all proceedings for infringement that may be
+instituted in respect of the use, modification and redistribution of the
+Software. Nevertheless, should such proceedings be instituted against
+the Licensee, the Licensor shall provide it with technical and legal
+assistance for its defense. Such technical and legal assistance shall be
+decided on a case-by-case basis between the relevant Licensor and the
+Licensee pursuant to a memorandum of understanding. The Licensor
+disclaims any and all liability as regards the Licensee's use of the
+name of the Software. No warranty is given as regards the existence of
+prior rights over the name of the Software or as regards the existence
+of a trademark.
+
+
+ Article 10 - TERMINATION
+
+10.1 In the event of a breach by the Licensee of its obligations
+hereunder, the Licensor may automatically terminate this Agreement
+thirty (30) days after notice has been sent to the Licensee and has
+remained ineffective.
+
+10.2 A Licensee whose Agreement is terminated shall no longer be
+authorized to use, modify or distribute the Software. However, any
+licenses that it may have granted prior to termination of the Agreement
+shall remain valid subject to their having been granted in compliance
+with the terms and conditions hereof.
+
+
+ Article 11 - MISCELLANEOUS
+
+
+ 11.1 EXCUSABLE EVENTS
+
+Neither Party shall be liable for any or all delay, or failure to
+perform the Agreement, that may be attributable to an event of force
+majeure, an act of God or an outside cause, such as defective
+functioning or interruptions of the electricity or telecommunications
+networks, network paralysis following a virus attack, intervention by
+government authorities, natural disasters, water damage, earthquakes,
+fire, explosions, strikes and labor unrest, war, etc.
+
+11.2 Any failure by either Party, on one or more occasions, to invoke
+one or more of the provisions hereof, shall under no circumstances be
+interpreted as being a waiver by the interested Party of its right to
+invoke said provision(s) subsequently.
+
+11.3 The Agreement cancels and replaces any or all previous agreements,
+whether written or oral, between the Parties and having the same
+purpose, and constitutes the entirety of the agreement between said
+Parties concerning said purpose. No supplement or modification to the
+terms and conditions hereof shall be effective as between the Parties
+unless it is made in writing and signed by their duly authorized
+representatives.
+
+11.4 In the event that one or more of the provisions hereof were to
+conflict with a current or future applicable act or legislative text,
+said act or legislative text shall prevail, and the Parties shall make
+the necessary amendments so as to comply with said act or legislative
+text. All other provisions shall remain effective. Similarly, invalidity
+of a provision of the Agreement, for any reason whatsoever, shall not
+cause the Agreement as a whole to be invalid.
+
+
+ 11.5 LANGUAGE
+
+The Agreement is drafted in both French and English and both versions
+are deemed authentic.
+
+
+ Article 12 - NEW VERSIONS OF THE AGREEMENT
+
+12.1 Any person is authorized to duplicate and distribute copies of this
+Agreement.
+
+12.2 So as to ensure coherence, the wording of this Agreement is
+protected and may only be modified by the authors of the License, who
+reserve the right to periodically publish updates or new versions of the
+Agreement, each with a separate number. These subsequent versions may
+address new issues encountered by Free Software.
+
+12.3 Any Software distributed under a given version of the Agreement may
+only be subsequently distributed under the same version of the Agreement
+or a subsequent version.
+
+
+ Article 13 - GOVERNING LAW AND JURISDICTION
+
+13.1 The Agreement is governed by French law. The Parties agree to
+endeavor to seek an amicable solution to any disagreements or disputes
+that may arise during the performance of the Agreement.
+
+13.2 Failing an amicable solution within two (2) months as from their
+occurrence, and unless emergency proceedings are necessary, the
+disagreements or disputes shall be referred to the Paris Courts having
+jurisdiction, by the more diligent Party.
+
+
+Version 1.0 dated 2006-09-05.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/README Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,41 @@
+# IRINOTES backoffice
+
+Back office for the IRINOTES application
+
+## Installation
+
+Please follow the command below to bootstrap the project
+
+```shell
+$ mkdir -p run/{db,log,web}
+$ mkdir -p run/web/{media,static}
+$ cp .env.tmpl .env
+$ vi .env
+$ mkvirtualenv irinotes
+$ pip install requirements/dev.txt
+$ python manage.py migrate
+$ python manage.py collectstatic
+$ python manage.py createsuperuser
+$ python manage.py runserver
+
+```
+
+You can now visit the following url in your browser <http://127.0.0.1:8000> .
+
+Admin interface is at <http://127.0.0.1:8000/admin>
+
+## Usage
+
+TODO: Write usage instructions
+
+## History
+
+TODO: Write history
+
+## Credits
+
+TODO: Write credits
+
+## License
+
+TODO: Write license
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/irinotes/__init__.py Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,48 @@
+VERSION = (0, 0, 1, "final", 0)
+
+VERSION_STR = ".".join(map(lambda i:"%02d" % (i,), VERSION[:2]))
+
+###
+# https://github.com/django/django/blob/1.9.1/django/utils/version.py
+#
+def get_version(version=None):
+ "Returns a PEP 440-compliant version number from VERSION."
+ if not version:
+ version = VERSION
+ version = get_complete_version(version)
+
+ # Now build the two parts of the version number:
+ # main = X.Y[.Z]
+ # sub = .devN - for pre-alpha releases
+ # | {a|b|rc}N - for alpha, beta, and rc releases
+
+ main = get_main_version(version)
+
+ sub = ''
+ if version[3] == 'alpha' and version[4] == 0:
+ sub = '.dev'
+
+ elif version[3] != 'final':
+ mapping = {'alpha': 'a', 'beta': 'b', 'rc': 'rc'}
+ sub = mapping[version[3]] + str(version[4])
+
+ return str(main + sub)
+
+def get_complete_version(version):
+ """
+ then checks for correctness of the tuple provided.
+ """
+ assert len(version) == 5
+ assert version[3] in ('alpha', 'beta', 'rc', 'final')
+
+ return version
+
+def get_main_version(version=None):
+ "Returns main version (X.Y[.Z]) from VERSION."
+ version = get_complete_version(version)
+ parts = 2 if version[2] == 0 else 3
+ return '.'.join(str(x) for x in version[:parts])
+
+__version__ = get_version(VERSION)
+
+default_app_config = 'irinotes.apps.IriNotesConfig'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/irinotes/apps.py Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+class IriNotesConfig(AppConfig):
+ name = 'irinotes'
+ verbose_name = "IRI Notes app"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/irinotes/settings.py Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,189 @@
+"""
+Django settings for irinotes project.
+
+Generated by 'django-admin startproject' using Django 1.11.2.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/1.11/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/1.11/ref/settings/
+"""
+
+import logging
+
+from decouple import Csv, config
+from dj_database_url import parse as db_url
+from unipath import Path
+
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
+BASE_DIR = Path(__file__).parent
+
+RUN_DIR = BASE_DIR.parent.child('run')
+
+STATIC_ROOT = config('STATIC_ROOT', default=RUN_DIR.child('web').child('static'))
+MEDIA_ROOT = config('MEDIA_ROOT', default=RUN_DIR.child('web').child('media'))
+
+# base url
+BASE_URL = config('BASE_URL', default='')
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = config('SECRET_KEY', '@povoyn_1_3dhfjktisno5l_0)_l1+m8$&mr8r2-srvd+m-58d')
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = config('DEBUG', default=True, cast=bool)
+
+ALLOWED_HOSTS = config('ALLOWED_HOSTS', default='', cast=Csv())
+
+
+# Application definition
+
+INSTALLED_APPS = [
+ 'django.contrib.admin',
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+ 'colorful',
+ 'concurrency',
+ 'notes'
+]
+
+MIDDLEWARE = [
+ 'django.middleware.security.SecurityMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.common.CommonMiddleware',
+ 'django.middleware.csrf.CsrfViewMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+ 'django.middleware.clickjacking.XFrameOptionsMiddleware',
+]
+
+ROOT_URLCONF = 'irinotes.urls'
+
+TEMPLATES = [
+ {
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
+ 'DIRS': [],
+ 'APP_DIRS': True,
+ 'OPTIONS': {
+ 'context_processors': [
+ 'django.template.context_processors.debug',
+ 'django.template.context_processors.request',
+ 'django.contrib.auth.context_processors.auth',
+ 'django.contrib.messages.context_processors.messages',
+ ],
+ },
+ },
+]
+
+WSGI_APPLICATION = 'irinotes.wsgi.application'
+
+
+# Database
+# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
+
+DATABASES = {
+ 'default': config(
+ 'DATABASE_URL',
+ default='sqlite:///' + RUN_DIR.child('db').child('db.sqlite3'),
+ cast=db_url
+ )
+}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+ {
+ 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+ },
+]
+
+AUTH_USER_MODEL = 'notes.User'
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/1.11/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'UTC'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/1.11/howto/static-files/
+
+STATIC_URL = config('STATIC_URL', default=BASE_URL + '/static/')
+
+# Logger
+
+LOG_FILE = config('LOG_FILE', default=RUN_DIR.child('log').child('log.txt'))
+LOG_LEVEL = config('LOG_LEVEL', default=logging.DEBUG, cast=lambda l: logging.getLevelName(l))
+
+LOGGING = {
+ 'version': 1,
+ 'disable_existing_loggers': True,
+ 'filters': {
+ 'require_debug_false': {
+ '()': 'django.utils.log.RequireDebugFalse'
+ }
+ },
+ 'formatters' : {
+ 'simple' : {
+ 'format': "%(asctime)s - %(levelname)s : %(message)s",
+ },
+ 'semi-verbose': {
+ 'format': '%(levelname)s %(asctime)s %(module)s %(message)s'
+ },
+ },
+ 'handlers': {
+ 'mail_admins': {
+ 'level': 'ERROR',
+ 'filters': ['require_debug_false'],
+ 'class': 'django.utils.log.AdminEmailHandler'
+ },
+ 'stream_to_console': {
+ 'level': LOG_LEVEL,
+ 'class': 'logging.StreamHandler'
+ },
+ 'file': {
+ 'level': LOG_LEVEL,
+ 'class': 'logging.FileHandler',
+ 'filename': LOG_FILE,
+ 'formatter': 'semi-verbose',
+ },
+ },
+ 'loggers': {
+ 'django.request': {
+ 'handlers': ['file'],
+ 'level': LOG_LEVEL,
+ 'propagate': True,
+ },
+ 'irinotes': {
+ 'handlers': ['file'],
+ 'level': LOG_LEVEL,
+ 'propagate': True,
+ },
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/irinotes/urls.py Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,21 @@
+"""irinotes URL Configuration
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+ https://docs.djangoproject.com/en/1.11/topics/http/urls/
+Examples:
+Function views
+ 1. Add an import: from my_app import views
+ 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
+Class-based views
+ 1. Add an import: from other_app.views import Home
+ 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
+Including another URLconf
+ 1. Import the include() function: from django.conf.urls import url, include
+ 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
+"""
+from django.conf.urls import url
+from django.contrib import admin
+
+urlpatterns = [
+ url(r'^admin/', admin.site.urls),
+]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/irinotes/wsgi.py Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,16 @@
+"""
+WSGI config for irinotes project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "irinotes.settings")
+
+application = get_wsgi_application()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/manage.py Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+import os
+import sys
+
+if __name__ == "__main__":
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "irinotes.settings")
+ try:
+ from django.core.management import execute_from_command_line
+ except ImportError:
+ # The above import may fail for some other reason. Ensure that the
+ # issue is really that Django is missing to avoid masking other
+ # exceptions on Python 2.
+ try:
+ import django
+ except ImportError:
+ raise ImportError(
+ "Couldn't import Django. Are you sure it's installed and "
+ "available on your PYTHONPATH environment variable? Did you "
+ "forget to activate a virtual environment?"
+ )
+ raise
+ execute_from_command_line(sys.argv)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/notes/admin/__init__.py Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,22 @@
+"""
+Admin registrations
+"""
+from django.contrib import admin
+from django.contrib.auth.models import Group
+
+from ..models import User, Note, Session, Protocol, Category
+from .auth import UserAdmin
+from .auth import GroupAdmin
+
+
+# Re-register UserAdmin
+admin.site.register(User, UserAdmin)
+
+# Re-register GroupAdmin
+admin.site.unregister(Group)
+admin.site.register(Group, GroupAdmin)
+
+admin.site.register(Note)
+admin.site.register(Session)
+admin.site.register(Protocol)
+admin.site.register(Category)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/notes/admin/auth.py Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,25 @@
+from django.contrib import admin
+from django.contrib.auth.admin import GroupAdmin as BaseGroupAdmin
+from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
+
+from notes.models import GroupProfile, UserProfile
+
+
+# Define an inline admin descriptor for Employee model
+# which acts a bit like a singleton
+class UserProfileInline(admin.StackedInline):
+ model = UserProfile
+ can_delete = False
+
+# Define a new User admin
+class UserAdmin(BaseUserAdmin):
+ inlines = (UserProfileInline, )
+
+
+class GroupProfileInline(admin.StackedInline):
+ model = GroupProfile
+ can_delete = False
+
+
+class GroupAdmin(BaseGroupAdmin):
+ inlines = (GroupProfileInline, )
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/notes/apps.py Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+
+class NotesConfig(AppConfig):
+ name = 'notes'
Binary file src/notes/locale/en/LC_MESSAGES/django.mo has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/notes/locale/en/LC_MESSAGES/django.po Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,157 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2017-06-08 15:29+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: models/auth.py:11
+msgid "User"
+msgstr "User"
+
+#: models/auth.py:12
+msgid "Users"
+msgstr "Users"
+
+#: models/auth.py:17
+msgid "UserProfile"
+msgstr "User profile"
+
+#: models/auth.py:18
+msgid "UserProfiles"
+msgstr "User profiles"
+
+#: models/auth.py:25
+msgid "GroupProfile"
+msgstr "Group profile"
+
+#: models/auth.py:26
+msgid "GroupProfiles"
+msgstr "Group profiles"
+
+#: models/base.py:18
+msgid "Model|created"
+msgstr "created"
+
+#: models/base.py:19
+msgid "Model|updated"
+msgstr "updated"
+
+#: models/base.py:20
+msgid "Model|ext_id"
+msgstr "external id"
+
+#: models/base.py:21
+msgid "Model|version"
+msgstr "version"
+
+#: models/category.py:13
+msgid "Protocol|title"
+msgstr "title"
+
+#: models/category.py:16
+msgid "Protocol"
+msgstr "Protocol"
+
+#: models/category.py:17
+msgid "Protocols"
+msgstr "Protocols"
+
+#: models/category.py:22
+msgid "Category|title"
+msgstr "title"
+
+#: models/category.py:23
+msgid "Category|color"
+msgstr "color"
+
+#: models/category.py:24
+msgid "Category|need_comment"
+msgstr "need comment"
+
+#: models/category.py:25
+msgid "Category|description"
+msgstr "description"
+
+#: models/category.py:28
+msgid "Category|protocol"
+msgstr "protocol"
+
+#: models/category.py:33
+msgid "Category"
+msgstr "Category"
+
+#: models/category.py:34
+msgid "Categories"
+msgstr "Categories"
+
+#: models/core.py:13
+msgid "Session"
+msgstr "Session"
+
+#: models/core.py:14
+msgid "Sessions"
+msgstr "Sessions"
+
+#: models/core.py:20
+msgid "Session|title"
+msgstr "title"
+
+#: models/core.py:21
+msgid "Session|description"
+msgstr "description"
+
+#: models/core.py:22
+msgid "Session|protocol"
+msgstr "protocol"
+
+#: models/core.py:26
+msgid "Note"
+msgstr "Note"
+
+#: models/core.py:27
+msgid "Notes"
+msgstr "Notes"
+
+#: models/core.py:30
+msgid "Note|tc_start"
+msgstr "start timecode"
+
+#: models/core.py:31
+msgid "Note|tc_end"
+msgstr "end timeocde"
+
+#: models/core.py:32
+msgid "Note|session"
+msgstr "session"
+
+#: models/core.py:33
+msgid "Note|text_plain"
+msgstr "text plain"
+
+#: models/core.py:34
+msgid "Note|text_html"
+msgstr "text html"
+
+#: models/core.py:35
+msgid "Note|text_raw"
+msgstr "text raw"
+
+#: models/core.py:36
+msgid "Note|margin_note"
+msgstr "margin note"
+
+#: models/core.py:37
+msgid "Note|categorization"
+msgstr "categorization"
Binary file src/notes/locale/fr/LC_MESSAGES/django.mo has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/notes/locale/fr/LC_MESSAGES/django.po Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,158 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2017-06-08 15:29+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+#: models/auth.py:11
+msgid "User"
+msgstr "Utilisateur"
+
+#: models/auth.py:12
+msgid "Users"
+msgstr "Utilisateurs"
+
+#: models/auth.py:17
+msgid "UserProfile"
+msgstr "Profil utilisateur"
+
+#: models/auth.py:18
+msgid "UserProfiles"
+msgstr "Profils utilisateur"
+
+#: models/auth.py:25
+msgid "GroupProfile"
+msgstr "Profile groupe"
+
+#: models/auth.py:26
+msgid "GroupProfiles"
+msgstr "Profiles groupe"
+
+#: models/base.py:18
+msgid "Model|created"
+msgstr "créé"
+
+#: models/base.py:19
+msgid "Model|updated"
+msgstr "mis à jour"
+
+#: models/base.py:20
+msgid "Model|ext_id"
+msgstr "identifiant externe"
+
+#: models/base.py:21
+msgid "Model|version"
+msgstr "version"
+
+#: models/category.py:13
+msgid "Protocol|title"
+msgstr "titre"
+
+#: models/category.py:16
+msgid "Protocol"
+msgstr "Protocole"
+
+#: models/category.py:17
+msgid "Protocols"
+msgstr "Protocoles"
+
+#: models/category.py:22
+msgid "Category|title"
+msgstr "titre"
+
+#: models/category.py:23
+msgid "Category|color"
+msgstr "couleur"
+
+#: models/category.py:24
+msgid "Category|need_comment"
+msgstr "a un commentaire"
+
+#: models/category.py:25
+msgid "Category|description"
+msgstr "description"
+
+#: models/category.py:28
+msgid "Category|protocol"
+msgstr "protocole"
+
+#: models/category.py:33
+msgid "Category"
+msgstr "Categorie"
+
+#: models/category.py:34
+msgid "Categories"
+msgstr "Categories"
+
+#: models/core.py:13
+msgid "Session"
+msgstr "Session"
+
+#: models/core.py:14
+msgid "Sessions"
+msgstr "Sessions"
+
+#: models/core.py:20
+msgid "Session|title"
+msgstr "titre"
+
+#: models/core.py:21
+msgid "Session|description"
+msgstr "description"
+
+#: models/core.py:22
+msgid "Session|protocol"
+msgstr "protocole"
+
+#: models/core.py:26
+msgid "Note"
+msgstr "Note"
+
+#: models/core.py:27
+msgid "Notes"
+msgstr "Notes"
+
+#: models/core.py:30
+msgid "Note|tc_start"
+msgstr "timecode début"
+
+#: models/core.py:31
+msgid "Note|tc_end"
+msgstr "timecode fin"
+
+#: models/core.py:32
+msgid "Note|session"
+msgstr "session"
+
+#: models/core.py:33
+msgid "Note|text_plain"
+msgstr "texte seul"
+
+#: models/core.py:34
+msgid "Note|text_html"
+msgstr "texte html"
+
+#: models/core.py:35
+msgid "Note|text_raw"
+msgstr "texte brut"
+
+#: models/core.py:36
+msgid "Note|margin_note"
+msgstr "note de marge"
+
+#: models/core.py:37
+msgid "Note|categorization"
+msgstr "catégorisation"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/notes/migrations/0001_initial.py Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,117 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.2 on 2017-06-08 15:10
+from __future__ import unicode_literals
+
+import concurrency.fields
+from django.conf import settings
+import django.contrib.auth.models
+import django.contrib.auth.validators
+from django.db import migrations, models
+import django.db.models.deletion
+import django.utils.timezone
+import uuid
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ('auth', '0008_alter_user_username_max_length'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='User',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('password', models.CharField(max_length=128, verbose_name='password')),
+ ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
+ ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
+ ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
+ ('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')),
+ ('last_name', models.CharField(blank=True, max_length=30, verbose_name='last name')),
+ ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
+ ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
+ ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
+ ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
+ ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
+ ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
+ ],
+ options={
+ 'verbose_name': 'User',
+ 'verbose_name_plural': 'Users',
+ },
+ managers=[
+ ('objects', django.contrib.auth.models.UserManager()),
+ ],
+ ),
+ migrations.CreateModel(
+ name='GroupProfile',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('description', models.TextField(blank=True, null=True)),
+ ('group', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='auth.Group')),
+ ],
+ options={
+ 'verbose_name': 'GroupProfile',
+ 'verbose_name_plural': 'GroupProfiles',
+ },
+ ),
+ migrations.CreateModel(
+ name='Note',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('created', models.DateTimeField(auto_now_add=True, verbose_name='Model|created')),
+ ('updated', models.DateTimeField(auto_now=True, verbose_name='Model|updated')),
+ ('ext_id', models.UUIDField(default=uuid.uuid4, unique=True, verbose_name='Model|ext_id')),
+ ('version', concurrency.fields.AutoIncVersionField(default=1, help_text='record revision number', verbose_name='Model|version')),
+ ('tc_start', models.DateTimeField()),
+ ('tc_end', models.DateTimeField()),
+ ('text_plain', models.TextField(blank=True, null=True, verbose_name='Note|text_plain')),
+ ('text_html', models.TextField(blank=True, null=True, verbose_name='Note|text_html')),
+ ('text_raw', models.TextField(blank=True, null=True, verbose_name='Note|text_raw')),
+ ('margin_note', models.TextField(blank=True, null=True, verbose_name='Note|margin_note')),
+ ('categorization', models.TextField(blank=True, null=True, verbose_name='Note|categorization')),
+ ],
+ options={
+ 'verbose_name': 'Note',
+ 'verbose_name_plural': 'Notes',
+ 'ordering': ['tc_start'],
+ },
+ ),
+ migrations.CreateModel(
+ name='Session',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('created', models.DateTimeField(auto_now_add=True, verbose_name='Model|created')),
+ ('updated', models.DateTimeField(auto_now=True, verbose_name='Model|updated')),
+ ('ext_id', models.UUIDField(default=uuid.uuid4, unique=True, verbose_name='Model|ext_id')),
+ ('version', concurrency.fields.AutoIncVersionField(default=1, help_text='record revision number', verbose_name='Model|version')),
+ ('title', models.TextField(blank=True, null=True, verbose_name='Session|title')),
+ ('description', models.TextField(blank=True, null=True, verbose_name='Session|description')),
+ ('protocol', models.TextField(blank=True, null=True, verbose_name='Session|protocol')),
+ ('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+ ],
+ options={
+ 'verbose_name': 'Session',
+ 'verbose_name_plural': 'Sessions',
+ },
+ ),
+ migrations.CreateModel(
+ name='UserProfile',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+ ],
+ options={
+ 'verbose_name': 'UserProfile',
+ 'verbose_name_plural': 'UserProfiles',
+ },
+ ),
+ migrations.AddField(
+ model_name='note',
+ name='session',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='notes.Session', verbose_name='Note|session'),
+ ),
+ ]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/notes/models/__init__.py Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,8 @@
+"""
+Models for notes
+"""
+from .auth import User, UserProfile, GroupProfile
+from .core import Note, Session
+from .category import Protocol, Category
+
+__all__ = ["User", "UserProfile", "GroupProfile", "Note", "Session", "Protocol", "Category"]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/notes/models/auth.py Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,27 @@
+"""
+auth module that defines irinotes' users and group
+"""
+from django.contrib.auth.models import AbstractUser, Group
+from django.db import models
+from django.utils.translation import ugettext_lazy as _
+
+
+class User(AbstractUser):
+ class Meta:
+ verbose_name = _('User')
+ verbose_name_plural = _('Users')
+
+class UserProfile(models.Model):
+ user = models.OneToOneField(User, on_delete=models.CASCADE)
+ class Meta:
+ verbose_name = _('UserProfile')
+ verbose_name_plural = _('UserProfiles')
+
+
+class GroupProfile(models.Model):
+ group = models.OneToOneField(Group, unique=True, on_delete=models.CASCADE)
+ description = models.TextField(null=True, blank=True)
+ class Meta:
+ verbose_name = _('GroupProfile')
+ verbose_name_plural = _('GroupProfiles')
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/notes/models/base.py Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,27 @@
+"""
+base abstract models
+"""
+import uuid
+
+from concurrency.fields import AutoIncVersionField
+from django.db import models
+from django.utils.translation import ugettext_lazy as _
+
+
+class ModelManager(models.Manager):
+ def get_by_natural_key(self, ext_id):
+ return self.get(ext_id=ext_id)
+
+class Model(models.Model):
+ objects = ModelManager()
+
+ created = models.DateTimeField(auto_now_add=True, verbose_name=_('Model|created'))
+ updated = models.DateTimeField(auto_now=True, verbose_name=_('Model|updated'))
+ ext_id = models.UUIDField(unique=True, default=uuid.uuid4, verbose_name=_('Model|ext_id'))
+ version = AutoIncVersionField(verbose_name=_('Model|version'))
+
+ def natural_key(self):
+ return (self.ext_id, )
+
+ class Meta:
+ abstract = True
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/notes/models/category.py Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,34 @@
+"""
+models for metacategories and protocol
+"""
+from colorful.fields import RGBColorField
+from django.db import models
+from django.utils.translation import ugettext_lazy as _
+
+from .base import Model
+from .auth import GroupProfile
+
+
+class Protocol(Model):
+ title = models.CharField(max_length=255, verbose_name=_('Protocol|title'))
+ group_profile = models.OneToOneField(GroupProfile, on_delete=models.CASCADE)
+ class Meta:
+ verbose_name = _('Protocol')
+ verbose_name_plural = _('Protocols')
+
+
+
+class Category(models.Model):
+ title = models.CharField(max_length=255, verbose_name=_('Category|title'))
+ color = RGBColorField(verbose_name=_('Category|color'))
+ need_comment = models.BooleanField(default=False, verbose_name=_('Category|need_comment'))
+ description = models.TextField(null=True, blank=True, verbose_name=_('Category|description'))
+ protocol = models.ForeignKey(
+ Protocol,
+ verbose_name=_('Category|protocol'),
+ related_name='categories',
+ on_delete=models.CASCADE
+ )
+ class Meta:
+ verbose_name = _('Category')
+ verbose_name_plural = _('Categories')
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/notes/models/core.py Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,38 @@
+"""
+irinotes core module
+"""
+from django.conf import settings
+from django.db import models
+from django.utils.translation import ugettext_lazy as _
+
+from .base import Model
+
+
+class Session(Model):
+ class Meta:
+ verbose_name = _('Session')
+ verbose_name_plural = _('Sessions')
+
+ owner = models.ForeignKey(
+ settings.AUTH_USER_MODEL,
+ on_delete=models.CASCADE,
+ )
+ title = models.TextField(null=True, blank=True, verbose_name=_('Session|title'))
+ description = models.TextField(null=True, blank=True, verbose_name=_('Session|description'))
+ protocol = models.TextField(null=True, blank=True, verbose_name=_('Session|protocol'))
+
+class Note(Model):
+ class Meta:
+ verbose_name = _('Note')
+ verbose_name_plural = _('Notes')
+ ordering = ["tc_start"]
+
+ tc_start = models.DateTimeField(verbose_name=_('Note|tc_start'))
+ tc_end = models.DateTimeField(verbose_name=_('Note|tc_end'))
+ session = models.ForeignKey(Session, on_delete=models.CASCADE, verbose_name=_('Note|session'))
+ text_plain = models.TextField(null=True, blank=True, verbose_name=_('Note|text_plain'))
+ text_html = models.TextField(null=True, blank=True, verbose_name=_('Note|text_html'))
+ text_raw = models.TextField(null=True, blank=True, verbose_name=_('Note|text_raw'))
+ margin_note = models.TextField(null=True, blank=True, verbose_name=_('Note|margin_note'))
+ categorization = models.TextField(null=True, blank=True, verbose_name=_('Note|categorization'))
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/notes/tests.py Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/notes/views.py Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,3 @@
+from django.shortcuts import render
+
+# Create your views here.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/requirements/base.txt Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,11 @@
+dj-database-url==0.4.2
+Django==1.11.2
+django-colorful==1.2
+django-concurrency==1.3.2
+django-guardian==1.4.8
+djangorestframework==3.6.3
+irinotes==0.0.1
+python-decouple==3.0
+pytz==2017.2
+six==1.10.0
+Unipath==1.1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/requirements/base.txt.in Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,2 @@
+# must run "pip install -r base.txt.in" in src/requirements
+-e ..
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/requirements/dev.txt Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,1 @@
+-r base.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/requirements/prod.txt Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,4 @@
+-r base.txt
+pylibmc
+uWSGI
+psycopg2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/setup.py Thu Jun 08 17:57:57 2017 +0200
@@ -0,0 +1,156 @@
+import os
+try:
+ from setuptools import setup
+except ImportError:
+ from distutils.core import setup
+from distutils.command.install_data import install_data
+from distutils.command.install import INSTALL_SCHEMES
+import sys
+
+
+class osx_install_data(install_data):
+ """
+ On MacOS, the platform-specific lib dir is /System/Library/Framework/Python/.../
+ which is wrong. Python 2.5 supplied with MacOS 10.5 has an Apple-specific fix
+ for this in distutils.command.install_data#306. It fixes install_lib but not
+ install_data, which is why we roll our own install_data class.
+ """
+
+ def finalize_options(self):
+ """
+ By the time finalize_options is called, install.install_lib is set to the
+ fixed directory, so we set the installdir to install_lib. The
+ install_data class uses ('install_data', 'install_dir') instead.
+ """
+ self.set_undefined_options('install', ('install_lib', 'install_dir'))
+ install_data.finalize_options(self)
+
+def fullsplit(path, result=None):
+ """
+ Split a pathname into components (the opposite of os.path.join) in a
+ platform-neutral way.
+ """
+ if result is None:
+ result = []
+ head, tail = os.path.split(path)
+ if head == '':
+ return [tail] + result
+ if head == path:
+ return result
+ return fullsplit(head, [tail] + result)
+
+
+def launch_setup(setup_script_name, setup_script_args):
+ """
+ Start setup
+ """
+ if sys.platform == "darwin":
+ cmdclasses = {'install_data': osx_install_data}
+ else:
+ cmdclasses = {'install_data': install_data}
+
+
+ root_dir = os.path.dirname(__file__)
+ if root_dir != '':
+ os.chdir(root_dir)
+ source_dirs = ['irinotes', 'notes']
+
+ version_variables = {}
+ try:
+ with open(os.path.join(source_dirs[0], "__init__.py")) as f:
+ code = compile(f.read(), "__init__.py", 'exec')
+ exec(code, version_variables)
+ except:
+ pass
+
+ version = version_variables['__version__']
+
+ packages, data_files = [], []
+
+ for source_dir in source_dirs:
+ for dirpath, dirnames, filenames in os.walk(source_dir):
+ # Ignore dirnames that start with '.'
+ for i, dirname in enumerate(dirnames):
+ if dirname.startswith('.') or dirname.startswith('__pycache__'): del dirnames[i]
+ if '__init__.py' in filenames:
+ packages.append('.'.join(fullsplit(dirpath)))
+ elif filenames:
+ data_files.append([dirpath, [os.path.join(dirpath, f) for f in filenames]])
+
+
+ # Tell distutils to put the data_files in platform-specific installation
+ # locations. See here for an explanation:
+ # http://groups.google.com/group/comp.lang.python/browse_thread/thread/35ec7b2fed36eaec/2105ee4d9e8042cb
+ for scheme in INSTALL_SCHEMES.values():
+ scheme['data'] = scheme['purelib']
+
+ # Small hack for working with bdist_wininst.
+ # See http://mail.python.org/pipermail/distutils-sig/2004-August/004134.html
+ if len(sys.argv) > 1 and sys.argv[1] == 'bdist_wininst':
+ for file_info in data_files:
+ file_info[0] = '\\PURELIB\\%s' % file_info[0]
+
+ #write MANIFEST.in
+
+ with open("MANIFEST.in", "w") as m:
+ m.write("include CHANGES\n")
+ m.write("include LICENSE\n")
+ m.write("include README\n")
+ m.write("include MANIFEST.in\n")
+ m.write("include requirements/base.txt\n")
+ m.write("include requirements/dev.txt\n")
+ m.write("include requirements/prod.txt\n")
+ for entry in data_files:
+ file_list = entry[1]
+ for filename in file_list:
+ m.write("include %s\n" % (filename))
+
+ long_description = ''
+ with open('README', 'r') as f:
+ long_description = f.read()
+
+ setup(
+ script_name=setup_script_name,
+ script_args=setup_script_args,
+ name='irinotes',
+ version=version,
+ author='IRI',
+ author_email='contact@iri.centrepompidou.fr',
+ packages=packages,
+ data_files=data_files,
+ cmdclass=cmdclasses,
+ scripts=[],
+ url='http://www.iri.centrepompidou.fr/dev/hg/irinotes',
+ license='CECILL-C',
+ description='projet Irinotes',
+ long_description=long_description,
+ classifiers=[
+ 'Development Status :: 4 - Beta',
+ 'Environment :: Web Environment',
+ 'Framework :: Django',
+ 'Intended Audience :: Developers',
+ 'License :: Ceccil-B',
+ 'Operating System :: OS Independent',
+ 'Programming Language :: Python',
+ 'Topic :: Utilities'
+ ],
+ install_requires=[
+ "Django >= 1.11",
+ "python-decouple",
+ "Unipath",
+ "dj-database-url",
+ "six",
+ "djangorestframework >= 3.6",
+ "django-guardian >= 1.4",
+ "django-colorful",
+ "django-concurrency"
+ ],
+ )
+
+
+if __name__ == "__main__":
+
+ script_name = os.path.basename(sys.argv[0])
+ script_args = sys.argv[1:]
+
+ launch_setup(script_name, script_args)