Project for the UPV to develop an app like BlaBlaCar but only for UPV people.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

first version of journeys app

Marcos Gabarda 148786cb

+2079
+29
.editorconfig
··· 1 + # http://editorconfig.org 2 + 3 + root = true 4 + 5 + [*] 6 + charset = utf-8 7 + end_of_line = lf 8 + insert_final_newline = true 9 + trim_trailing_whitespace = true 10 + 11 + [*.{py,rst,ini}] 12 + indent_style = space 13 + indent_size = 4 14 + 15 + [*.py] 16 + line_length=120 17 + known_first_party=project_name 18 + multi_line_output=3 19 + default_section=THIRDPARTY 20 + 21 + [*.{html,css,scss,json,yml,js}] 22 + indent_style = space 23 + indent_size = 2 24 + 25 + [*.md] 26 + trim_trailing_whitespace = false 27 + 28 + [Makefile] 29 + indent_style = tab
.env

This is a binary file and will not be displayed.

+64
.gitignore
··· 1 + # OSX 2 + .DS_Store 3 + .AppleDouble 4 + .LSOverride 5 + ._* 6 + 7 + # Windows 8 + Thumbs.db 9 + Desktop.ini 10 + 11 + # Basics 12 + *.py[cod] 13 + __pycache__ 14 + 15 + # Translations 16 + *.mo 17 + *.pot 18 + 19 + # Logs 20 + *.log 21 + logs/* 22 + 23 + # Packaging files: 24 + *.egg* 25 + 26 + # Sphinx docs: 27 + docs/_build 28 + 29 + # SQLite3 database files: 30 + upvcarshare/*.db 31 + 32 + # Pycharm 33 + .idea 34 + 35 + # Eclipse 36 + .project 37 + .pydevproject 38 + .settings 39 + 40 + # Linux Editors 41 + *~ 42 + \#*\# 43 + /.emacs.desktop 44 + /.emacs.desktop.lock 45 + .elc 46 + auto-save-list 47 + tramp 48 + .\#* 49 + *.swp 50 + *.swo 51 + 52 + # Npm packates 53 + node_modules 54 + 55 + # virtual environments 56 + .env 57 + 58 + # Ignore oracle 59 + oracle-xe-11.2.0-1.0.x86_64.rpm 60 + 61 + # Project specific 62 + upvcarshare/public 63 + upvcarshare/static/css/bundle.css 64 + upvcarshare/static/js/bundle.js
+14
README.rst
··· 1 + UPV Car Share Project 2 + ===================== 3 + 4 + Made with Python 3 and Django with :heart:. 5 + 6 + Install Spatialite 7 + ------------------ 8 + 9 + Install SpatiaLite with brew on Mac OS X:: 10 + 11 + brew update 12 + brew install spatialite-tools 13 + brew install gdal 14 +
+216
docs/Makefile
··· 1 + # Makefile for Sphinx documentation 2 + # 3 + 4 + # You can set these variables from the command line. 5 + SPHINXOPTS = 6 + SPHINXBUILD = sphinx-build 7 + PAPER = 8 + BUILDDIR = _build 9 + 10 + # User-friendly check for sphinx-build 11 + ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 + $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 + endif 14 + 15 + # Internal variables. 16 + PAPEROPT_a4 = -D latex_paper_size=a4 17 + PAPEROPT_letter = -D latex_paper_size=letter 18 + ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 + # the i18n builder cannot share the environment and doctrees with the others 20 + I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 + 22 + .PHONY: help 23 + help: 24 + @echo "Please use \`make <target>' where <target> is one of" 25 + @echo " html to make standalone HTML files" 26 + @echo " dirhtml to make HTML files named index.html in directories" 27 + @echo " singlehtml to make a single large HTML file" 28 + @echo " pickle to make pickle files" 29 + @echo " json to make JSON files" 30 + @echo " htmlhelp to make HTML files and a HTML help project" 31 + @echo " qthelp to make HTML files and a qthelp project" 32 + @echo " applehelp to make an Apple Help Book" 33 + @echo " devhelp to make HTML files and a Devhelp project" 34 + @echo " epub to make an epub" 35 + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 + @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 + @echo " text to make text files" 39 + @echo " man to make manual pages" 40 + @echo " texinfo to make Texinfo files" 41 + @echo " info to make Texinfo files and run them through makeinfo" 42 + @echo " gettext to make PO message catalogs" 43 + @echo " changes to make an overview of all changed/added/deprecated items" 44 + @echo " xml to make Docutils-native XML files" 45 + @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 + @echo " linkcheck to check all external links for integrity" 47 + @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 + @echo " coverage to run coverage check of the documentation (if enabled)" 49 + 50 + .PHONY: clean 51 + clean: 52 + rm -rf $(BUILDDIR)/* 53 + 54 + .PHONY: html 55 + html: 56 + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 57 + @echo 58 + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 59 + 60 + .PHONY: dirhtml 61 + dirhtml: 62 + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 63 + @echo 64 + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 65 + 66 + .PHONY: singlehtml 67 + singlehtml: 68 + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 69 + @echo 70 + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 71 + 72 + .PHONY: pickle 73 + pickle: 74 + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 75 + @echo 76 + @echo "Build finished; now you can process the pickle files." 77 + 78 + .PHONY: json 79 + json: 80 + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 81 + @echo 82 + @echo "Build finished; now you can process the JSON files." 83 + 84 + .PHONY: htmlhelp 85 + htmlhelp: 86 + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 87 + @echo 88 + @echo "Build finished; now you can run HTML Help Workshop with the" \ 89 + ".hhp project file in $(BUILDDIR)/htmlhelp." 90 + 91 + .PHONY: qthelp 92 + qthelp: 93 + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 94 + @echo 95 + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 96 + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 97 + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Chargy.qhcp" 98 + @echo "To view the help file:" 99 + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Chargy.qhc" 100 + 101 + .PHONY: applehelp 102 + applehelp: 103 + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp 104 + @echo 105 + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." 106 + @echo "N.B. You won't be able to view it unless you put it in" \ 107 + "~/Library/Documentation/Help or install it in your application" \ 108 + "bundle." 109 + 110 + .PHONY: devhelp 111 + devhelp: 112 + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 113 + @echo 114 + @echo "Build finished." 115 + @echo "To view the help file:" 116 + @echo "# mkdir -p $$HOME/.local/share/devhelp/Chargy" 117 + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Chargy" 118 + @echo "# devhelp" 119 + 120 + .PHONY: epub 121 + epub: 122 + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 123 + @echo 124 + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 125 + 126 + .PHONY: latex 127 + latex: 128 + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 129 + @echo 130 + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 131 + @echo "Run \`make' in that directory to run these through (pdf)latex" \ 132 + "(use \`make latexpdf' here to do that automatically)." 133 + 134 + .PHONY: latexpdf 135 + latexpdf: 136 + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 137 + @echo "Running LaTeX files through pdflatex..." 138 + $(MAKE) -C $(BUILDDIR)/latex all-pdf 139 + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 140 + 141 + .PHONY: latexpdfja 142 + latexpdfja: 143 + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 144 + @echo "Running LaTeX files through platex and dvipdfmx..." 145 + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 146 + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 147 + 148 + .PHONY: text 149 + text: 150 + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 151 + @echo 152 + @echo "Build finished. The text files are in $(BUILDDIR)/text." 153 + 154 + .PHONY: man 155 + man: 156 + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 157 + @echo 158 + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 159 + 160 + .PHONY: texinfo 161 + texinfo: 162 + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 163 + @echo 164 + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 165 + @echo "Run \`make' in that directory to run these through makeinfo" \ 166 + "(use \`make info' here to do that automatically)." 167 + 168 + .PHONY: info 169 + info: 170 + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 171 + @echo "Running Texinfo files through makeinfo..." 172 + make -C $(BUILDDIR)/texinfo info 173 + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 174 + 175 + .PHONY: gettext 176 + gettext: 177 + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 178 + @echo 179 + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 180 + 181 + .PHONY: changes 182 + changes: 183 + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 184 + @echo 185 + @echo "The overview file is in $(BUILDDIR)/changes." 186 + 187 + .PHONY: linkcheck 188 + linkcheck: 189 + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 190 + @echo 191 + @echo "Link check complete; look for any errors in the above output " \ 192 + "or in $(BUILDDIR)/linkcheck/output.txt." 193 + 194 + .PHONY: doctest 195 + doctest: 196 + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 197 + @echo "Testing of doctests in the sources finished, look at the " \ 198 + "results in $(BUILDDIR)/doctest/output.txt." 199 + 200 + .PHONY: coverage 201 + coverage: 202 + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage 203 + @echo "Testing of coverage in the sources finished, look at the " \ 204 + "results in $(BUILDDIR)/coverage/python.txt." 205 + 206 + .PHONY: xml 207 + xml: 208 + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 209 + @echo 210 + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 211 + 212 + .PHONY: pseudoxml 213 + pseudoxml: 214 + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 215 + @echo 216 + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
+291
docs/conf.py
··· 1 + #!/usr/bin/env python3 2 + # -*- coding: utf-8 -*- 3 + # 4 + # UPV Car Share documentation build configuration file, created by 5 + # sphinx-quickstart on Thu Mar 10 20:44:35 2016. 6 + # 7 + # This file is execfile()d with the current directory set to its 8 + # containing dir. 9 + # 10 + # Note that not all possible configuration values are present in this 11 + # autogenerated file. 12 + # 13 + # All configuration values have a default; values that are commented out 14 + # serve to show the default. 15 + 16 + import sys 17 + import os 18 + 19 + # If extensions (or modules to document with autodoc) are in another directory, 20 + # add these directories to sys.path here. If the directory is relative to the 21 + # documentation root, use os.path.abspath to make it absolute, like shown here. 22 + #sys.path.insert(0, os.path.abspath('.')) 23 + 24 + # -- General configuration ------------------------------------------------ 25 + 26 + # If your documentation needs a minimal Sphinx version, state it here. 27 + #needs_sphinx = '1.0' 28 + 29 + # Add any Sphinx extension module names here, as strings. They can be 30 + # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 31 + # ones. 32 + extensions = ['sphinxcontrib.httpdomain'] 33 + 34 + # Add any paths that contain templates here, relative to this directory. 35 + templates_path = ['_templates'] 36 + 37 + # The suffix(es) of source filenames. 38 + # You can specify multiple suffix as a list of string: 39 + # source_suffix = ['.rst', '.md'] 40 + source_suffix = '.rst' 41 + 42 + # The encoding of source files. 43 + #source_encoding = 'utf-8-sig' 44 + 45 + # The master toctree document. 46 + master_doc = 'index' 47 + 48 + # General information about the project. 49 + project = 'UPV Car Share Project' 50 + copyright = '2016, Marcos Gabarda' 51 + author = 'Marcos Gabarda' 52 + 53 + # The version info for the project you're documenting, acts as replacement for 54 + # |version| and |release|, also used in various other places throughout the 55 + # built documents. 56 + # 57 + # The short X.Y version. 58 + version = '0.1.0' 59 + # The full version, including alpha/beta/rc tags. 60 + release = '0.1.0' 61 + 62 + # The language for content autogenerated by Sphinx. Refer to documentation 63 + # for a list of supported languages. 64 + # 65 + # This is also used if you do content translation via gettext catalogs. 66 + # Usually you set "language" from the command line for these cases. 67 + language = 'es' 68 + 69 + # There are two options for replacing |today|: either, you set today to some 70 + # non-false value, then it is used: 71 + #today = '' 72 + # Else, today_fmt is used as the format for a strftime call. 73 + #today_fmt = '%B %d, %Y' 74 + 75 + # List of patterns, relative to source directory, that match files and 76 + # directories to ignore when looking for source files. 77 + exclude_patterns = ['_build'] 78 + 79 + # The reST default role (used for this markup: `text`) to use for all 80 + # documents. 81 + #default_role = None 82 + 83 + # If true, '()' will be appended to :func: etc. cross-reference text. 84 + #add_function_parentheses = True 85 + 86 + # If true, the current module name will be prepended to all description 87 + # unit titles (such as .. function::). 88 + #add_module_names = True 89 + 90 + # If true, sectionauthor and moduleauthor directives will be shown in the 91 + # output. They are ignored by default. 92 + #show_authors = False 93 + 94 + # The name of the Pygments (syntax highlighting) style to use. 95 + pygments_style = 'sphinx' 96 + 97 + # A list of ignored prefixes for module index sorting. 98 + #modindex_common_prefix = [] 99 + 100 + # If true, keep warnings as "system message" paragraphs in the built documents. 101 + #keep_warnings = False 102 + 103 + # If true, `todo` and `todoList` produce output, else they produce nothing. 104 + todo_include_todos = False 105 + 106 + 107 + # -- Options for HTML output ---------------------------------------------- 108 + 109 + # The theme to use for HTML and HTML Help pages. See the documentation for 110 + # a list of builtin themes. 111 + html_theme = 'alabaster' 112 + 113 + on_rtd = os.environ.get('READTHEDOCS', None) == 'True' 114 + 115 + if not on_rtd: 116 + import sphinx_rtd_theme 117 + html_theme = "sphinx_rtd_theme" 118 + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] 119 + 120 + # Theme options are theme-specific and customize the look and feel of a theme 121 + # further. For a list of options available for each theme, see the 122 + # documentation. 123 + #html_theme_options = {} 124 + 125 + # Add any paths that contain custom themes here, relative to this directory. 126 + #html_theme_path = [] 127 + 128 + # The name for this set of Sphinx documents. If None, it defaults to 129 + # "<project> v<release> documentation". 130 + #html_title = None 131 + 132 + # A shorter title for the navigation bar. Default is the same as html_title. 133 + #html_short_title = None 134 + 135 + # The name of an image file (relative to this directory) to place at the top 136 + # of the sidebar. 137 + #html_logo = None 138 + 139 + # The name of an image file (relative to this directory) to use as a favicon of 140 + # the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 141 + # pixels large. 142 + #html_favicon = None 143 + 144 + # Add any paths that contain custom static files (such as style sheets) here, 145 + # relative to this directory. They are copied after the builtin static files, 146 + # so a file named "default.css" will overwrite the builtin "default.css". 147 + html_static_path = ['_static'] 148 + 149 + # Add any extra paths that contain custom files (such as robots.txt or 150 + # .htaccess) here, relative to this directory. These files are copied 151 + # directly to the root of the documentation. 152 + #html_extra_path = [] 153 + 154 + # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 155 + # using the given strftime format. 156 + #html_last_updated_fmt = '%b %d, %Y' 157 + 158 + # If true, SmartyPants will be used to convert quotes and dashes to 159 + # typographically correct entities. 160 + #html_use_smartypants = True 161 + 162 + # Custom sidebar templates, maps document names to template names. 163 + #html_sidebars = {} 164 + 165 + # Additional templates that should be rendered to pages, maps page names to 166 + # template names. 167 + #html_additional_pages = {} 168 + 169 + # If false, no module index is generated. 170 + #html_domain_indices = True 171 + 172 + # If false, no index is generated. 173 + #html_use_index = True 174 + 175 + # If true, the index is split into individual pages for each letter. 176 + #html_split_index = False 177 + 178 + # If true, links to the reST sources are added to the pages. 179 + #html_show_sourcelink = True 180 + 181 + # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 182 + #html_show_sphinx = True 183 + 184 + # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 185 + #html_show_copyright = True 186 + 187 + # If true, an OpenSearch description file will be output, and all pages will 188 + # contain a <link> tag referring to it. The value of this option must be the 189 + # base URL from which the finished HTML is served. 190 + #html_use_opensearch = '' 191 + 192 + # This is the file name suffix for HTML files (e.g. ".xhtml"). 193 + #html_file_suffix = None 194 + 195 + # Language to be used for generating the HTML full-text search index. 196 + # Sphinx supports the following languages: 197 + # 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja' 198 + # 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr' 199 + #html_search_language = 'en' 200 + 201 + # A dictionary with options for the search language support, empty by default. 202 + # Now only 'ja' uses this config value 203 + #html_search_options = {'type': 'default'} 204 + 205 + # The name of a javascript file (relative to the configuration directory) that 206 + # implements a search results scorer. If empty, the default will be used. 207 + #html_search_scorer = 'scorer.js' 208 + 209 + # Output file base name for HTML help builder. 210 + htmlhelp_basename = 'Upvcarsharedoc' 211 + 212 + # -- Options for LaTeX output --------------------------------------------- 213 + 214 + latex_elements = { 215 + # The paper size ('letterpaper' or 'a4paper'). 216 + #'papersize': 'letterpaper', 217 + 218 + # The font size ('10pt', '11pt' or '12pt'). 219 + #'pointsize': '10pt', 220 + 221 + # Additional stuff for the LaTeX preamble. 222 + #'preamble': '', 223 + 224 + # Latex figure (float) alignment 225 + #'figure_align': 'htbp', 226 + } 227 + 228 + # Grouping the document tree into LaTeX files. List of tuples 229 + # (source start file, target name, title, 230 + # author, documentclass [howto, manual, or own class]). 231 + latex_documents = [ 232 + (master_doc, 'UPVCarShare.tex', 'UPV Car Share Documentation', 233 + 'Marcos Gabarda', 'manual'), 234 + ] 235 + 236 + # The name of an image file (relative to this directory) to place at the top of 237 + # the title page. 238 + #latex_logo = None 239 + 240 + # For "manual" documents, if this is true, then toplevel headings are parts, 241 + # not chapters. 242 + #latex_use_parts = False 243 + 244 + # If true, show page references after internal links. 245 + #latex_show_pagerefs = False 246 + 247 + # If true, show URL addresses after external links. 248 + #latex_show_urls = False 249 + 250 + # Documents to append as an appendix to all manuals. 251 + #latex_appendices = [] 252 + 253 + # If false, no module index is generated. 254 + #latex_domain_indices = True 255 + 256 + 257 + # -- Options for manual page output --------------------------------------- 258 + 259 + # One entry per manual page. List of tuples 260 + # (source start file, name, description, authors, manual section). 261 + man_pages = [ 262 + (master_doc, 'upvcarshare', 'UPV Car Share Documentation', 263 + [author], 1) 264 + ] 265 + 266 + # If true, show URL addresses after external links. 267 + #man_show_urls = False 268 + 269 + 270 + # -- Options for Texinfo output ------------------------------------------- 271 + 272 + # Grouping the document tree into Texinfo files. List of tuples 273 + # (source start file, target name, title, author, 274 + # dir menu entry, description, category) 275 + texinfo_documents = [ 276 + (master_doc, 'UPVCarShare', 'UPV Car Share Documentation', 277 + author, 'UPVCarShare', 'One line description of project.', 278 + 'Miscellaneous'), 279 + ] 280 + 281 + # Documents to append as an appendix to all manuals. 282 + #texinfo_appendices = [] 283 + 284 + # If false, no module index is generated. 285 + #texinfo_domain_indices = True 286 + 287 + # How to display URL addresses: 'footnote', 'no', or 'inline'. 288 + #texinfo_show_urls = 'footnote' 289 + 290 + # If true, do not generate a @detailmenu in the "Top" node's menu. 291 + #texinfo_no_detailmenu = False
+20
docs/index.rst
··· 1 + .. Chargy documentation master file, created by 2 + sphinx-quickstart on Thu Mar 10 20:44:35 2016. 3 + You can adapt this file completely to your liking, but it should at least 4 + contain the root `toctree` directive. 5 + 6 + Documentación de UPV Car Share Project 7 + ====================================== 8 + 9 + Content: 10 + 11 + .. toctree:: 12 + :maxdepth: 2 13 + 14 + 15 + Indices and tables 16 + ================== 17 + 18 + * :ref:`genindex` 19 + * :ref:`modindex` 20 + * :ref:`search`
+4
env.example
··· 1 + DATABASE_URL= 2 + DJANGO_DEBUG= 3 + DJANGO_ALLOWED_HOSTS= 4 + DJANGO_SECRET_KEY=
+70
gulpfile.js
··· 1 + 'use strict'; 2 + var gulp = require('gulp'); 3 + var sass = require('gulp-sass'); 4 + var rename = require("gulp-rename"); 5 + var config = require('./package.json'); 6 + 7 + // Helper for handle static paths 8 + // ----------------------------------------------------------------------------- 9 + var pathsConfig = function (appName) { 10 + var app = appName || config.name; 11 + return { 12 + app: app, 13 + templates: app + '/templates', 14 + css: app + '/static/css', 15 + sass: app + '/static/sass', 16 + fonts: app + '/static/fonts', 17 + images: app + '/static/images', 18 + js: app + '/static/js', 19 + manageScript: app + 'manage.py' 20 + } 21 + }; 22 + 23 + 24 + // CSS Task 25 + // ----------------------------------------------------------------------------- 26 + var cssTask = function (options) { 27 + 28 + // Default include node_modules to SASS include paths 29 + var sassOptions = { 30 + includePaths: ['./node_modules/'], 31 + errLogToConsole: true 32 + }; 33 + 34 + // Common 'run' code for each options 35 + var run = function (options) { 36 + options = sassOptions || options; 37 + gulp.src(pathsConfig().sass + '/project.scss') 38 + .pipe(sass(options).on('error', sass.logError)) 39 + .pipe(rename('bundle.css')) 40 + .pipe(gulp.dest(pathsConfig().css)); 41 + }; 42 + 43 + // Run for development with watch 44 + if (options.development) { 45 + run(); 46 + gulp.watch(options.watch, run); 47 + // Run for production with compressed 48 + } else { 49 + run({outputStyle: 'compressed'}); 50 + } 51 + 52 + }; 53 + 54 + // Default Task 55 + // ----------------------------------------------------------------------------- 56 + // Starts our development workflow 57 + gulp.task('default', function () { 58 + cssTask({ 59 + development: true, 60 + watch: pathsConfig().sass + "/**/*.scss" 61 + }) 62 + }); 63 + 64 + // Deploy Task 65 + // ----------------------------------------------------------------------------- 66 + gulp.task('deploy', function () { 67 + cssTask({ 68 + development: false 69 + }) 70 + });
+16
package.json
··· 1 + { 2 + "name": "upvcarshare", 3 + "version": "0.1.0", 4 + "description": "UPV Car Share project", 5 + "repository": "https://github.com/marcosgabarda/upvcarshare", 6 + "license": "MIT", 7 + "dependencies": {}, 8 + "devDependencies": { 9 + "bootstrap": "^4.0.0-alpha.2", 10 + "gulp": "^3.9.1", 11 + "gulp-rename": "^1.2.2", 12 + "gulp-sass": "^2.3.1", 13 + "node-sass": "^3.4.2", 14 + "yuglify": "^0.1.4" 15 + } 16 + }
+11
requirements/base.txt
··· 1 + django==1.9.5 2 + django-environ==0.4.0 3 + django-braces==1.8.1 4 + django-extensions==1.6.3 5 + logutils==0.3.3 6 + django-model-utils==2.5 7 + djangorestframework==3.3.3 8 + sphinx==1.4.1 9 + sphinx-rtd-theme==0.1.9 10 + sphinxcontrib-httpdomain==1.4.0 11 + django-pipeline==1.6.8
+5
requirements/local.txt
··· 1 + -r base.txt 2 + coverage==4.0.3 3 + django-test-plus==1.0.12 4 + factory_boy==2.7.0 5 + django-debug-toolbar==1.4
upvcarshare/config/__init__.py

This is a binary file and will not be displayed.

+2
upvcarshare/config/settings/__init__.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import
+321
upvcarshare/config/settings/base.py
··· 1 + # -*- coding: utf-8 -*- 2 + from os.path import basename 3 + from sys import path 4 + 5 + import environ 6 + 7 + env = environ.Env() 8 + 9 + # PATH CONFIGURATION 10 + # ------------------------------------------------------------------------------ 11 + # environ.Path value to the django repo directory: 12 + ROOT_DIR = environ.Path(__file__) - 4 13 + 14 + # environ.Path value to the project directory: 15 + APPS_DIR = environ.Path(__file__) - 3 16 + 17 + # Absolute filesystem path to the config directory: 18 + CONFIG_ROOT = str(APPS_DIR.path("config")) 19 + 20 + # Absolute filesystem path to the project directory: 21 + PROJECT_ROOT = str(APPS_DIR) 22 + 23 + # Absolute filesystem path to the django repo directory: 24 + DJANGO_ROOT = str(ROOT_DIR) 25 + 26 + # Project folder: 27 + PROJECT_FOLDER = basename(PROJECT_ROOT) 28 + 29 + # Project name: 30 + PROJECT_NAME = basename(PROJECT_ROOT).capitalize() 31 + 32 + # Project domain: 33 + PROJECT_DOMAIN = '%s.com' % PROJECT_NAME.lower() 34 + 35 + # Add our project to our pythonpath, this way we don't need to type our project 36 + # name in our dotted import paths: 37 + path.append(CONFIG_ROOT) 38 + 39 + # DEBUG CONFIGURATION 40 + # ------------------------------------------------------------------------------ 41 + # See: https://docs.djangoproject.com/en/dev/ref/settings/#debug 42 + DEBUG = env.bool('DJANGO_DEBUG', False) 43 + API_DEBUG = DEBUG 44 + 45 + # MANAGER CONFIGURATION 46 + # ------------------------------------------------------------------------------ 47 + # See: https://docs.djangoproject.com/en/dev/ref/settings/#admins 48 + ADMINS = ( 49 + ("Marcos Gabarda", 'hey@marcosgabarda.com'), 50 + ) 51 + 52 + # See: https://docs.djangoproject.com/en/dev/ref/settings/#managers 53 + MANAGERS = ADMINS 54 + 55 + 56 + # GENERAL CONFIGURATION 57 + # ------------------------------------------------------------------------------ 58 + # https://docs.djangoproject.com/en/dev/ref/settings/#time-zone 59 + TIME_ZONE = 'UTC' 60 + 61 + # https://docs.djangoproject.com/en/dev/ref/settings/#language-code 62 + LANGUAGE_CODE = 'es-es' 63 + 64 + # https://docs.djangoproject.com/en/dev/ref/settings/#site-id 65 + SITE_ID = 1 66 + 67 + # https://docs.djangoproject.com/en/dev/ref/settings/#use-i18n 68 + USE_I18N = True 69 + 70 + # https://docs.djangoproject.com/en/dev/ref/settings/#use-l10n 71 + USE_L10N = True 72 + 73 + # https://docs.djangoproject.com/en/dev/ref/settings/#use-tz 74 + USE_TZ = True 75 + 76 + # FIXTURE CONFIGURATION 77 + # ------------------------------------------------------------------------------ 78 + # See: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-FIXTURE_DIRS 79 + FIXTURE_DIRS = ( 80 + str(APPS_DIR.path('fixtures')), 81 + ) 82 + 83 + # MIDDLEWARE CONFIGURATION 84 + # ------------------------------------------------------------------------------ 85 + # https://docs.djangoproject.com/en/dev/ref/settings/#middleware-classes 86 + MIDDLEWARE_CLASSES = ( 87 + 'django.middleware.gzip.GZipMiddleware', 88 + 'django.contrib.sessions.middleware.SessionMiddleware', 89 + 'django.middleware.common.CommonMiddleware', 90 + 'django.middleware.csrf.CsrfViewMiddleware', 91 + 'django.contrib.auth.middleware.AuthenticationMiddleware', 92 + 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 93 + 'django.contrib.messages.middleware.MessageMiddleware', 94 + 'django.middleware.clickjacking.XFrameOptionsMiddleware', 95 + ) 96 + 97 + # EMAIL 98 + # ------------------------------------------------------------------------------ 99 + # See: https://docs.djangoproject.com/en/dev/ref/settings/#email-backend 100 + DEFAULT_FROM_EMAIL = env('DJANGO_DEFAULT_FROM_EMAIL', default='{} <noreply@example.com>'.format(PROJECT_NAME)) 101 + EMAIL_SUBJECT_PREFIX = env('DJANGO_EMAIL_SUBJECT_PREFIX', default='[{}] '.format(PROJECT_NAME)) 102 + SERVER_EMAIL = env('DJANGO_SERVER_EMAIL', default=DEFAULT_FROM_EMAIL) 103 + 104 + 105 + # TEMPLATE CONFIGURATION 106 + # ------------------------------------------------------------------------------ 107 + # https://docs.djangoproject.com/en/dev/ref/templates/ 108 + TEMPLATES = [ 109 + { 110 + 'BACKEND': 'django.template.backends.django.DjangoTemplates', 111 + 'DIRS': [ 112 + str(APPS_DIR.path("templates")) 113 + ], 114 + 'OPTIONS': { 115 + 'context_processors': [ 116 + 'django.contrib.auth.context_processors.auth', 117 + 'django.template.context_processors.debug', 118 + 'django.template.context_processors.i18n', 119 + 'django.template.context_processors.media', 120 + 'django.template.context_processors.static', 121 + 'django.template.context_processors.tz', 122 + 'django.contrib.messages.context_processors.messages', 123 + 'django.template.context_processors.request', 124 + ], 125 + 'loaders': [ 126 + 'django.template.loaders.filesystem.Loader', 127 + 'django.template.loaders.app_directories.Loader', 128 + ], 129 + 'string_if_invalid': 'NULL', 130 + }, 131 + }, 132 + ] 133 + 134 + 135 + # APP CONFIGURATION 136 + # ------------------------------------------------------------------------------ 137 + # https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps 138 + DJANGO_APPS = ( 139 + 'django.contrib.auth', 140 + 'django.contrib.contenttypes', 141 + 'django.contrib.sessions', 142 + 'django.contrib.sites', 143 + 'django.contrib.messages', 144 + 'django.contrib.staticfiles', 145 + 'django.contrib.humanize', 146 + 'django.contrib.admin', 147 + 'django.contrib.admindocs', 148 + ) 149 + 150 + THIRD_PARTY_APPS = ( 151 + 'django_extensions', 152 + 'rest_framework', 153 + 'rest_framework.authtoken', 154 + 'pipeline', 155 + ) 156 + 157 + PROJECT_APPS = ( 158 + 'users', 159 + 'journeys', 160 + ) 161 + 162 + INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + PROJECT_APPS 163 + 164 + # MEDIA CONFIGURATION 165 + # ------------------------------------------------------------------------------ 166 + # https://docs.djangoproject.com/en/dev/ref/settings/#media-root 167 + MEDIA_ROOT = str(APPS_DIR.path("media")) 168 + 169 + # https://docs.djangoproject.com/en/dev/ref/settings/#media-url 170 + MEDIA_URL = '/media/' 171 + 172 + # STATIC FILE CONFIGURATION 173 + # ------------------------------------------------------------------------------ 174 + # https://docs.djangoproject.com/en/dev/ref/settings/#static-root 175 + STATIC_ROOT = str(APPS_DIR.path("public")) 176 + 177 + # https://docs.djangoproject.com/en/dev/ref/settings/#static-url 178 + STATIC_URL = '/static/' 179 + 180 + # https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS 181 + STATICFILES_DIRS = ( 182 + str(APPS_DIR.path("static")), 183 + ) 184 + 185 + # https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-STATICFILES_STORAGE 186 + STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage' 187 + 188 + # https://docs.djangoproject.com/en/dev/ref/settings/#staticfiles-finders 189 + STATICFILES_FINDERS = [ 190 + 'django.contrib.staticfiles.finders.FileSystemFinder', 191 + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 192 + ] 193 + 194 + 195 + # URL Configuration 196 + # ------------------------------------------------------------------------------ 197 + ROOT_URLCONF = 'config.urls' 198 + 199 + # See: https://docs.djangoproject.com/en/dev/ref/settings/#wsgi-application 200 + WSGI_APPLICATION = 'config.wsgi.application' 201 + 202 + # AUTHENTICATION CONFIGURATION 203 + # ------------------------------------------------------------------------------ 204 + # Some really nice defaults 205 + ACCOUNT_AUTHENTICATION_METHOD = 'username' 206 + ACCOUNT_EMAIL_REQUIRED = True 207 + ACCOUNT_EMAIL_VERIFICATION = 'mandatory' 208 + 209 + # Custom user app defaults 210 + # Select the correct user model 211 + AUTH_USER_MODEL = 'users.User' 212 + LOGIN_REDIRECT_URL = 'users:redirect' 213 + LOGIN_URL = 'account_login' 214 + 215 + # https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators 216 + AUTH_PASSWORD_VALIDATORS = [ 217 + { 218 + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 219 + }, 220 + { 221 + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 222 + }, 223 + { 224 + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 225 + }, 226 + { 227 + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 228 + }, 229 + ] 230 + 231 + AUTHENTICATION_BACKENDS = ( 232 + 'django.contrib.auth.backends.ModelBackend', 233 + ) 234 + 235 + # TESTING CONFIGURATION 236 + # ------------------------------------------------------------------------------ 237 + TEST_RUNNER = 'django.test.runner.DiscoverRunner' 238 + 239 + # LOGGING CONFIGURATION 240 + # ------------------------------------------------------------------------------ 241 + # https://docs.djangoproject.com/en/dev/ref/settings/#logging 242 + LOGGING = { 243 + 'version': 1, 244 + 'disable_existing_loggers': False, 245 + 'filters': { 246 + 'production_only': { 247 + '()': 'django.utils.log.RequireDebugFalse', 248 + }, 249 + 'development_only': { 250 + '()': 'django.utils.log.RequireDebugTrue', 251 + } 252 + }, 253 + 'formatters': { 254 + 'verbose': { 255 + 'format': '[%(asctime)s] %(levelname)-8s [%(name)s:%(lineno)s] %(message)s', 256 + 'datefmt': '%m/%d/%Y %H:%M:%S', 257 + }, 258 + 'simple': { 259 + 'format': '%(levelname)-8s [%(name)s:%(lineno)s] %(message)s', 260 + }, 261 + }, 262 + 'handlers': { 263 + 'null': { 264 + 'level': 'DEBUG', 265 + 'class': 'logging.NullHandler', 266 + }, 267 + 'default': { 268 + 'level': 'DEBUG', 269 + 'class': 'logutils.colorize.ColorizingStreamHandler', 270 + }, 271 + 'console_dev': { 272 + 'level': 'DEBUG', 273 + 'filters': ['development_only'], 274 + 'class': 'logutils.colorize.ColorizingStreamHandler', 275 + 'formatter': 'simple', 276 + }, 277 + 'console_prod': { 278 + 'level': 'INFO', 279 + 'filters': ['production_only'], 280 + 'class': 'logutils.colorize.ColorizingStreamHandler', 281 + 'formatter': 'simple', 282 + }, 283 + 'mail_admins': { 284 + 'level': 'ERROR', 285 + 'filters': ['production_only'], 286 + 'class': 'django.utils.log.AdminEmailHandler', 287 + 'include_html': True, 288 + }, 289 + }, 290 + # Catch-all modules that use logging 291 + # Writes to console and file on development, only to console on production 292 + 'root': { 293 + 'handlers': ['console_dev', 'console_prod'], 294 + 'level': 'DEBUG', 295 + }, 296 + 'loggers': { 297 + # Ignore DisallowedHost 298 + 'django.security.DisallowedHost': { 299 + 'handlers': ['null'], 300 + 'propagate': False, 301 + }, 302 + # Email admins when 500 error occurs 303 + 'django.request': { 304 + 'handlers': ['mail_admins'], 305 + 'level': 'ERROR', 306 + 'propagate': False, 307 + }, 308 + } 309 + } 310 + 311 + # REST FRAMEWORK CONFIGURATION 312 + # ------------------------------------------------------------------------------ 313 + # http://www.django-rest-framework.org/ 314 + REST_FRAMEWORK = { 315 + 'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAdminUser',), 316 + 'PAGE_SIZE': 10, 317 + 'DEFAULT_AUTHENTICATION_CLASSES': ( 318 + 'rest_framework.authentication.TokenAuthentication', 319 + 'rest_framework.authentication.SessionAuthentication', 320 + ) 321 + }
+33
upvcarshare/config/settings/local.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import 3 + from config.settings.base import * 4 + 5 + # DEBUG 6 + # ------------------------------------------------------------------------------ 7 + DEBUG = env.bool('DJANGO_DEBUG', default=True) 8 + TEMPLATES[0]['OPTIONS']['debug'] = DEBUG 9 + 10 + # SECRET CONFIGURATION 11 + # ------------------------------------------------------------------------------ 12 + # See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key 13 + # Note: This key only used for development and testing. 14 + SECRET_KEY = env('DJANGO_SECRET_KEY', default='o#bpi3*=nzn5r-9i!db1&h&oo0%5wmzudw-q2054z9n)u8=uez') 15 + 16 + # DATABASE CONFIGURATION 17 + # ------------------------------------------------------------------------------ 18 + # See: https://docs.djangoproject.com/en/dev/ref/settings/#databases 19 + DATABASES = { 20 + 'default': env.db( 21 + 'DATABASE_URL', default='spatialite:///{}'.format(str(APPS_DIR.path('{}.db'.format(PROJECT_NAME.lower())))) 22 + ), 23 + } 24 + DATABASES['default']['ATOMIC_REQUESTS'] = True 25 + SPATIALITE_LIBRARY_PATH = env('DJANGO_EMAIL_BACKEND', default='/usr/local/lib/mod_spatialite.dylib') 26 + 27 + # EMAIL 28 + # ------------------------------------------------------------------------------ 29 + # See: https://docs.djangoproject.com/en/dev/ref/settings/#email-backend 30 + EMAIL_BACKEND = env( 31 + 'DJANGO_EMAIL_BACKEND', 32 + default='django.core.mail.backends.console.EmailBackend' 33 + )
+26
upvcarshare/config/settings/production.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import 3 + from config.settings.base import * 4 + 5 + # SITE CONFIGURATION 6 + # ------------------------------------------------------------------------------ 7 + # Hosts/domain names that are valid for this site 8 + # See https://docs.djangoproject.com/en/1.6/ref/settings/#allowed-hosts 9 + ALLOWED_HOSTS = env.list('DJANGO_ALLOWED_HOSTS', default=['example.com']) 10 + 11 + # SECRET CONFIGURATION 12 + # ------------------------------------------------------------------------------ 13 + # See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key 14 + # Raises ImproperlyConfigured exception if DJANGO_SECRET_KEY not in os.environ 15 + SECRET_KEY = env('DJANGO_SECRET_KEY') 16 + 17 + # DATABASE CONFIGURATION 18 + # ------------------------------------------------------------------------------ 19 + # See: https://docs.djangoproject.com/en/dev/ref/settings/#databases 20 + DATABASES = { 21 + # Raises ImproperlyConfigured exception if DATABASE_URL not in os.environ 22 + 'default': env.db( 23 + 'DATABASE_URL', default='spatialite://{}'.format(str(APPS_DIR.path('{}.db'.format(PROJECT_NAME.lower())))) 24 + ), 25 + } 26 + DATABASES['default']['ATOMIC_REQUESTS'] = True
+25
upvcarshare/config/settings/test.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import 3 + from config.settings.base import * 4 + 5 + # SECRET CONFIGURATION 6 + # ------------------------------------------------------------------------------ 7 + # See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key 8 + # Note: This key only used for development and testing. 9 + SECRET_KEY = env('DJANGO_SECRET_KEY', default='o#bpi3*=nzn5r-9i!db1&h&oo0%5wmzudw-q2054z9n)u8=uez') 10 + 11 + # DATABASE CONFIGURATION 12 + # ------------------------------------------------------------------------------ 13 + # Database in memory for tests 14 + DATABASES = { 15 + "default": { 16 + "ENGINE": "django.contrib.gis.db.backends.spatialite", 17 + "NAME": ":memory:", 18 + "USER": "", 19 + "PASSWORD": "", 20 + "HOST": "", 21 + "PORT": "", 22 + }, 23 + } 24 + DATABASES['default']['ATOMIC_REQUESTS'] = True 25 + SPATIALITE_LIBRARY_PATH = env('DJANGO_EMAIL_BACKEND', default='/usr/local/lib/mod_spatialite.dylib')
+7
upvcarshare/config/urls.py
··· 1 + # -*- coding: utf-8 -*- 2 + from django.conf.urls import url 3 + from django.contrib import admin 4 + 5 + urlpatterns = [ 6 + url(r'^admin/', admin.site.urls), 7 + ]
+16
upvcarshare/config/wsgi.py
··· 1 + """ 2 + WSGI config for upvcarshare project. 3 + 4 + It exposes the WSGI callable as a module-level variable named ``application``. 5 + 6 + For more information on this file, see 7 + https://docs.djangoproject.com/en/1.9/howto/deployment/wsgi/ 8 + """ 9 + 10 + import os 11 + 12 + from django.core.wsgi import get_wsgi_application 13 + 14 + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "upvcarshare.settings") 15 + 16 + application = get_wsgi_application()
+2
upvcarshare/core/__init__.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import
+23
upvcarshare/core/models.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import 3 + from django.contrib.gis.db import models 4 + from django_extensions.db.fields import CreationDateTimeField, ModificationDateTimeField 5 + from django.utils.translation import ugettext_lazy as _ 6 + 7 + 8 + class GisTimeStampedModel(models.Model): 9 + """ TimeStampedModel 10 + An abstract base class model that provides self-managed "created" and 11 + "modified" fields for geographic models. 12 + """ 13 + created = CreationDateTimeField(_('created')) 14 + modified = ModificationDateTimeField(_('modified')) 15 + 16 + def save(self, **kwargs): 17 + self.update_modified = kwargs.pop('update_modified', getattr(self, 'update_modified', True)) 18 + super(GisTimeStampedModel, self).save(**kwargs) 19 + 20 + class Meta: 21 + get_latest_by = 'modified' 22 + ordering = ('-modified', '-created',) 23 + abstract = True
+2
upvcarshare/core/tests/__init__.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import
+15
upvcarshare/journeys/__init__.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import 3 + from django.utils.translation import ugettext_lazy as _ 4 + 5 + GOING, RETURN = 0, 1 6 + JOURNEY_KINDS = ( 7 + (GOING, _("Going")), 8 + (RETURN, _("Return")), 9 + ) 10 + 11 + # Uses projected coordinate system for Spain. 12 + # See: https://epsg.io/2062 13 + DEFAULT_PROJECTED_SRID = 2062 14 + # Distance in meters 15 + DEFAULT_CAMPUS_DISTANCE = 500
+2
upvcarshare/journeys/api/__init__.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import
+2
upvcarshare/journeys/api/v1/__init__.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import
+2
upvcarshare/journeys/api/v1/resources.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import
+14
upvcarshare/journeys/exceptions.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import 3 + 4 + 5 + class NoFreePlaces(Exception): 6 + msg = "No free places for this journey." 7 + 8 + 9 + class AlreadyAPassenger(Exception): 10 + msg = "User is already a passenger." 11 + 12 + 13 + class NotAPassenger(Exception): 14 + msg = "The user is not a passenger of this journey."
+111
upvcarshare/journeys/managers.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import 3 + 4 + from functools import reduce 5 + from django.contrib.gis.db import models 6 + from django.contrib.gis.measure import D 7 + from django.db.models import Count, F, Q 8 + from django.utils import timezone 9 + 10 + from journeys import GOING, RETURN 11 + 12 + 13 + def recommended_condition(journey): 14 + """Creates a condition to mark a journey as recommended, based on kind and a 15 + needed journey. 16 + :param kind: 17 + :param journey: 18 + """ 19 + key = "residence{}" if journey.kind == GOING else "campus{}" 20 + return { 21 + key.format("__position__distance_lte"): ( 22 + getattr(journey, key.format("")).position, 23 + D(m=getattr(journey, key.format("")).distance) 24 + ) 25 + } 26 + 27 + 28 + class ResidenceManager(models.GeoManager): 29 + 30 + def smart_create(self, user): 31 + """Smart create using data from user.""" 32 + return self.create( 33 + address=user.default_address, 34 + position=user.default_position, 35 + ) 36 + 37 + 38 + class JourneyManager(models.GeoManager): 39 + """Manager for Journeys.""" 40 + 41 + def smart_create(self, user, origin, destination, departure, transport=None): 42 + """Enhanced method to create journeys""" 43 + assert origin.__class__.__name__.lower() == "residence" or \ 44 + origin.__class__.__name__.lower() == "campus" 45 + assert destination.__class__.__name__.lower() == "residence" or \ 46 + destination.__class__.__name__.lower() == "campus" 47 + assert destination.__class__ != origin.__class__ 48 + kind = GOING if origin.__class__.__name__.lower() == "residence" else RETURN 49 + data = { 50 + "user": user, 51 + "kind": kind, 52 + "departure": departure, 53 + origin.__class__.__name__.lower(): origin, 54 + destination.__class__.__name__.lower(): destination, 55 + } 56 + if transport is not None: 57 + data["driver"] = user 58 + data["free_places"] = transport.default_places 59 + return self.create(**data) 60 + 61 + def available(self, kind=None): 62 + """Gets all available journeys. 63 + :param kind: GOING, RETURN 64 + """ 65 + now = timezone.now() 66 + queryset = self.filter(driver__isnull=False, departure__gt=now) 67 + if kind is not None: 68 + queryset = queryset.filter(kind=kind) 69 + return queryset.\ 70 + annotate(total_passengers=Count("passengers")).\ 71 + filter(total_passengers__lt=F("free_places")) 72 + 73 + def nearby(self, geometry, distance, kind=None): 74 + """Gets available nearby journeys. 75 + :param distance: django.contrib.gis.measure.D 76 + :param geometry: django.contrib.gis.geos.GEOSGeometry 77 + :param kind: GOING, RETURN 78 + """ 79 + 80 + nearby = self.available(kind) 81 + if kind is not None: 82 + key = "residence{}" if kind == GOING else "campus{}" 83 + key = key.format("__position__distance_lte") 84 + nearby = nearby.filter(**{key: (geometry, distance)}) 85 + else: 86 + nearby = nearby.filter( 87 + Q(residence__position__distance_lte=(geometry, distance)) | 88 + Q(campus__position__distance_lte=(geometry, distance)) 89 + ) 90 + return nearby 91 + 92 + def needed(self, user, kind=None): 93 + """Journeys that given user needs a driver. 94 + :param kind: 95 + :param user: 96 + """ 97 + now = timezone.now() 98 + queryset = self.filter(user=user, driver__isnull=True, departure__gt=now) 99 + if kind is not None: 100 + queryset = queryset.filter(kind=kind) 101 + return queryset 102 + 103 + def recommended(self, user, kind=None): 104 + """Gets the journeys recommended for an user needs. 105 + :param user: 106 + :param kind: 107 + """ 108 + # Gets journeys needed by the user... 109 + needed_journeys = self.needed(user=user, kind=kind) 110 + conditions = [Q(**recommended_condition(journey=journey)) for journey in needed_journeys] 111 + return self.available(kind=kind).exclude(user=user).filter(reduce(lambda x, y: x | y, conditions))
+110
upvcarshare/journeys/migrations/0001_initial.py
··· 1 + # -*- coding: utf-8 -*- 2 + # Generated by Django 1.9.5 on 2016-05-16 13:05 3 + from __future__ import unicode_literals 4 + 5 + from django.conf import settings 6 + import django.contrib.gis.db.models.fields 7 + from django.db import migrations, models 8 + import django.db.models.deletion 9 + import django_extensions.db.fields 10 + 11 + 12 + class Migration(migrations.Migration): 13 + 14 + initial = True 15 + 16 + dependencies = [ 17 + migrations.swappable_dependency(settings.AUTH_USER_MODEL), 18 + ] 19 + 20 + operations = [ 21 + migrations.CreateModel( 22 + name='Campus', 23 + fields=[ 24 + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 25 + ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True, verbose_name='created')), 26 + ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True, verbose_name='modified')), 27 + ('name', models.CharField(blank=True, max_length=64, null=True)), 28 + ('position', django.contrib.gis.db.models.fields.PointField(srid=2062)), 29 + ('distance', models.PositiveIntegerField(help_text='radius of the node on meters')), 30 + ], 31 + options={ 32 + 'abstract': False, 33 + }, 34 + ), 35 + migrations.CreateModel( 36 + name='Journey', 37 + fields=[ 38 + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 39 + ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True, verbose_name='created')), 40 + ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True, verbose_name='modified')), 41 + ('kind', models.PositiveIntegerField(choices=[(0, 'Going'), (1, 'Return')])), 42 + ('free_places', models.PositiveIntegerField(default=4)), 43 + ('departure', models.DateTimeField()), 44 + ('disabled', models.BooleanField(default=False)), 45 + ('campus', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='journeys', to='journeys.Campus')), 46 + ('driver', models.ForeignKey(blank=True, help_text='user who drives during the journey', null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 47 + ], 48 + options={ 49 + 'ordering': ('-modified', '-created'), 50 + 'get_latest_by': 'modified', 51 + 'abstract': False, 52 + }, 53 + ), 54 + migrations.CreateModel( 55 + name='Passenger', 56 + fields=[ 57 + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 58 + ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True, verbose_name='created')), 59 + ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True, verbose_name='modified')), 60 + ('journey', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='passengers', to='journeys.Journey')), 61 + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 62 + ], 63 + ), 64 + migrations.CreateModel( 65 + name='Residence', 66 + fields=[ 67 + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 68 + ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True, verbose_name='created')), 69 + ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True, verbose_name='modified')), 70 + ('name', models.CharField(blank=True, max_length=64, null=True)), 71 + ('position', django.contrib.gis.db.models.fields.PointField(srid=2062)), 72 + ('distance', models.PositiveIntegerField(help_text='radius of the node on meters')), 73 + ('address', models.TextField()), 74 + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='residences', to=settings.AUTH_USER_MODEL)), 75 + ], 76 + options={ 77 + 'abstract': False, 78 + }, 79 + ), 80 + migrations.CreateModel( 81 + name='Transport', 82 + fields=[ 83 + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 84 + ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True, verbose_name='created')), 85 + ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True, verbose_name='modified')), 86 + ('name', models.CharField(blank=True, max_length=64, null=True)), 87 + ('default_places', models.PositiveIntegerField(default=4)), 88 + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transports', to=settings.AUTH_USER_MODEL)), 89 + ], 90 + options={ 91 + 'ordering': ('-modified', '-created'), 92 + 'get_latest_by': 'modified', 93 + 'abstract': False, 94 + }, 95 + ), 96 + migrations.AddField( 97 + model_name='journey', 98 + name='residence', 99 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='journeys', to='journeys.Residence'), 100 + ), 101 + migrations.AddField( 102 + model_name='journey', 103 + name='user', 104 + field=models.ForeignKey(help_text='user who creates the journey', on_delete=django.db.models.deletion.CASCADE, related_name='journeys', to=settings.AUTH_USER_MODEL), 105 + ), 106 + migrations.AlterUniqueTogether( 107 + name='passenger', 108 + unique_together=set([('user', 'journey')]), 109 + ), 110 + ]
upvcarshare/journeys/migrations/__init__.py

This is a binary file and will not be displayed.

+145
upvcarshare/journeys/models.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import 3 + 4 + from django.conf import settings 5 + from django.contrib.gis.db import models 6 + from django.contrib.gis.measure import D 7 + from django_extensions.db.models import TimeStampedModel 8 + from django.utils.translation import ugettext_lazy as _ 9 + 10 + from core.models import GisTimeStampedModel 11 + from journeys import JOURNEY_KINDS, GOING, RETURN, DEFAULT_CAMPUS_DISTANCE, DEFAULT_PROJECTED_SRID 12 + from journeys.exceptions import NoFreePlaces, NotAPassenger, AlreadyAPassenger 13 + from journeys.managers import JourneyManager, ResidenceManager 14 + 15 + 16 + class Place(GisTimeStampedModel): 17 + """Abstract class model to represent common data shared by residences and 18 + campus. 19 + 20 + Uses projected coordinate system for Spain. See: http://spatialreference.org/ref/epsg/2062/ 21 + """ 22 + name = models.CharField(max_length=64, blank=True, null=True) 23 + position = models.PointField(srid=DEFAULT_PROJECTED_SRID) 24 + distance = models.PositiveIntegerField(help_text=_("radius of the node on meters")) 25 + 26 + class Meta: 27 + abstract = True 28 + 29 + def position_wgs84(self): 30 + """Transforms position to WGS-84 system.""" 31 + return self.position.transform(4326) 32 + 33 + def nearby(self): 34 + """Abstract method to search nearby journeys.""" 35 + raise NotImplementedError() 36 + 37 + 38 + class Residence(Place): 39 + """A node where life a user, and my want to go back or departure from 40 + here. Each residence belongs to a user. 41 + """ 42 + user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="residences") 43 + address = models.TextField() 44 + 45 + objects = ResidenceManager() 46 + 47 + def nearby(self): 48 + """Search nearby journeys.""" 49 + return Journey.objects.nearby(kind=GOING, geometry=self.position, distance=D(m=self.distance)) 50 + 51 + 52 + class Campus(Place): 53 + """A node that represents an university campus.""" 54 + 55 + def nearby(self): 56 + """Search nearby journeys.""" 57 + return Journey.objects.nearby(kind=RETURN, geometry=self.position, distance=D(m=self.distance)) 58 + 59 + def save(self, **kwargs): 60 + if not self.distance: 61 + self.distance = DEFAULT_CAMPUS_DISTANCE 62 + super(Campus, self).save(**kwargs) 63 + 64 + 65 + class Journey(GisTimeStampedModel): 66 + """A model class to represent a journey between two node.""" 67 + user = models.ForeignKey( 68 + settings.AUTH_USER_MODEL, related_name="journeys", help_text=_("user who creates the journey") 69 + ) 70 + driver = models.ForeignKey( 71 + settings.AUTH_USER_MODEL, null=True, blank=True, help_text=_("user who drives during the journey") 72 + ) 73 + residence = models.ForeignKey("journeys.Residence", related_name="journeys") 74 + campus = models.ForeignKey("journeys.Campus", related_name="journeys") 75 + kind = models.PositiveIntegerField(choices=JOURNEY_KINDS) 76 + free_places = models.PositiveIntegerField(default=4) 77 + departure = models.DateTimeField() 78 + disabled = models.BooleanField(default=False) 79 + 80 + objects = JourneyManager() 81 + 82 + def origin(self): 83 + """Origin of the journey.""" 84 + if self.kind == GOING: 85 + return self.residence 86 + return self.campus 87 + 88 + def destination(self): 89 + """Destination of the journey.""" 90 + if self.kind == RETURN: 91 + return self.residence 92 + return self.campus 93 + 94 + def count_passengers(self): 95 + """Gets the count of passengers.""" 96 + return self.passengers.count() 97 + 98 + def current_free_places(self): 99 + """Gets the current number of free places.""" 100 + return self.free_places - self.count_passengers() 101 + 102 + def join_passenger(self, user): 103 + """A user joins a journey. 104 + :param user: 105 + """ 106 + if self.passengers.filter(user=user).exists() or self.driver == user: 107 + raise AlreadyAPassenger() 108 + if self.count_passengers() < self.free_places: 109 + return Passenger.objects.create( 110 + journey=self, 111 + user=user 112 + ) 113 + raise NoFreePlaces() 114 + 115 + def leave_passenger(self, user): 116 + """A user joins a journey. 117 + :param user: 118 + """ 119 + if not self.is_passenger(user=user): 120 + raise NotAPassenger() 121 + self.passengers.filter(user=user).delete() 122 + 123 + def is_passenger(self, user): 124 + return self.passengers.filter(user=user).exists() 125 + 126 + def recommended(self): 127 + if self.driver == self.user: 128 + return Journey.objects.none() 129 + Journey.objects.recommended(user=self.user, kind=self.kind, ) 130 + 131 + 132 + class Passenger(TimeStampedModel): 133 + """A user who has joined a journey.""" 134 + user = models.ForeignKey(settings.AUTH_USER_MODEL) 135 + journey = models.ForeignKey("journeys.Journey", related_name="passengers") 136 + 137 + class Meta: 138 + unique_together = ["user", "journey"] 139 + 140 + 141 + class Transport(TimeStampedModel): 142 + """Saves the transport data for a user.""" 143 + name = models.CharField(max_length=64, blank=True, null=True) 144 + user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="transports") 145 + default_places = models.PositiveIntegerField(default=4)
+2
upvcarshare/journeys/tests/__init__.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import
+45
upvcarshare/journeys/tests/factories.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import 3 + 4 + import datetime 5 + import factory 6 + from django.contrib.gis.geos import Point 7 + from django.utils import timezone 8 + 9 + from journeys import GOING, DEFAULT_PROJECTED_SRID 10 + from users.tests.factories import UserFactory 11 + 12 + 13 + class ResidenceFactory(factory.django.DjangoModelFactory): 14 + user = factory.SubFactory(UserFactory) 15 + position = factory.LazyFunction(lambda: Point(883877.34, 547084.05, srid=DEFAULT_PROJECTED_SRID)) 16 + distance = 500 17 + 18 + class Meta: 19 + model = "journeys.Residence" 20 + 21 + 22 + class CampusFactory(factory.django.DjangoModelFactory): 23 + name = "Vera" 24 + position = factory.LazyFunction(lambda: Point(887483.60, 547842.30, srid=DEFAULT_PROJECTED_SRID)) 25 + distance = 500 26 + 27 + class Meta: 28 + model = "journeys.Campus" 29 + 30 + 31 + class JourneyFactory(factory.django.DjangoModelFactory): 32 + user = factory.SubFactory(UserFactory) 33 + residence = factory.SubFactory(ResidenceFactory) 34 + campus = factory.SubFactory(CampusFactory) 35 + departure = factory.LazyFunction(lambda: timezone.now() + datetime.timedelta(days=1)) 36 + kind = GOING 37 + 38 + class Meta: 39 + model = "journeys.Journey" 40 + 41 + 42 + class TransportFactory(factory.django.DjangoModelFactory): 43 + 44 + class Meta: 45 + model = "journeys.Transport"
+228
upvcarshare/journeys/tests/test_models.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import 3 + 4 + import datetime 5 + 6 + from django.contrib.gis.geos import Point 7 + from django.contrib.gis.measure import D 8 + from django.utils import timezone 9 + from test_plus.test import TestCase 10 + 11 + from journeys import GOING, RETURN, DEFAULT_PROJECTED_SRID 12 + from journeys.exceptions import AlreadyAPassenger, NotAPassenger 13 + from journeys.models import Journey, Passenger 14 + from journeys.tests.factories import ResidenceFactory, CampusFactory, TransportFactory, JourneyFactory 15 + from users.tests.factories import UserFactory 16 + 17 + 18 + class JourneyTest(TestCase): 19 + """Test related with Journey model and manager methods.""" 20 + 21 + @staticmethod 22 + def _make_journey(kind=GOING): 23 + user = UserFactory() 24 + origin = ResidenceFactory(user=user) 25 + destination = CampusFactory() 26 + return JourneyFactory(user=user, residence=origin, campus=destination, kind=kind) 27 + 28 + def test_smart_create_no_transport(self): 29 + """Test smart create of a journey without transport.""" 30 + user = UserFactory() 31 + origin = ResidenceFactory(user=user) 32 + destination = CampusFactory() 33 + journey = Journey.objects.smart_create( 34 + user=user, origin=origin, destination=destination, departure=timezone.now() + datetime.timedelta(days=1) 35 + ) 36 + self.assertEquals(Journey.objects.count(), 1) 37 + self.assertEquals(Journey.objects.first(), journey) 38 + 39 + def test_smart_create(self): 40 + """Test smart create of a journey with transport.""" 41 + user = UserFactory() 42 + transport = TransportFactory(user=user) 43 + origin = ResidenceFactory(user=user) 44 + destination = CampusFactory() 45 + journey = Journey.objects.smart_create( 46 + user=user, origin=origin, destination=destination, departure=timezone.now() + datetime.timedelta(days=1), 47 + transport=transport 48 + ) 49 + self.assertEquals(Journey.objects.count(), 1) 50 + self.assertEquals(Journey.objects.first(), journey) 51 + self.assertEquals(journey.free_places, transport.default_places) 52 + self.assertEquals(journey.current_free_places(), transport.default_places) 53 + self.assertIsNotNone(journey.driver) 54 + self.assertEquals(user, journey.driver) 55 + 56 + def test_origin(self): 57 + user = UserFactory() 58 + origin = ResidenceFactory(user=user) 59 + destination = CampusFactory() 60 + journey = JourneyFactory(user=user, residence=origin, campus=destination, kind=GOING) 61 + self.assertEquals(journey.origin(), origin) 62 + 63 + def test_destination(self): 64 + user = UserFactory() 65 + origin = ResidenceFactory(user=user) 66 + destination = CampusFactory() 67 + journey = JourneyFactory(user=user, residence=origin, campus=destination, kind=GOING) 68 + self.assertEquals(journey.destination(), destination) 69 + 70 + def test_join_passenger(self): 71 + user = UserFactory() 72 + journey = self._make_journey() 73 + self.assertIsInstance(journey.join_passenger(user), Passenger) 74 + self.assertTrue(journey.is_passenger(user)) 75 + self.assertEquals(journey.count_passengers(), 1) 76 + 77 + def test_join_already_passenger(self): 78 + user = UserFactory() 79 + journey = self._make_journey() 80 + journey.join_passenger(user) 81 + try: 82 + journey.join_passenger(user) 83 + raised_exception = False 84 + except AlreadyAPassenger: 85 + raised_exception = True 86 + self.assertTrue(raised_exception) 87 + 88 + def test_leave_passenger(self): 89 + user = UserFactory() 90 + journey = self._make_journey() 91 + journey.join_passenger(user) 92 + journey.leave_passenger(user) 93 + self.assertFalse(journey.is_passenger(user)) 94 + 95 + def test_leave_no_passenger(self): 96 + user = UserFactory() 97 + journey = self._make_journey() 98 + try: 99 + journey.leave_passenger(user) 100 + raised_exception = False 101 + except NotAPassenger: 102 + raised_exception = True 103 + self.assertTrue(raised_exception) 104 + 105 + def test_available_going_query(self): 106 + # Creates the available journeys with driver... 107 + user1 = UserFactory() 108 + residence1 = ResidenceFactory(user=user1, position=Point(883877.34, 547084.05, srid=DEFAULT_PROJECTED_SRID)) 109 + user2 = UserFactory() 110 + residence2 = ResidenceFactory(user=user2, position=Point(882823.07, 545542.48, srid=DEFAULT_PROJECTED_SRID)) 111 + campus = CampusFactory() 112 + JourneyFactory(user=user1, driver=user1, residence=residence1, campus=campus) 113 + JourneyFactory(user=user2, driver=user2, residence=residence2, campus=campus) 114 + # Creates a journey without driver 115 + user3 = UserFactory() 116 + residence3 = ResidenceFactory(user=user3, position=Point(882454.58, 545877.33, srid=DEFAULT_PROJECTED_SRID)) 117 + JourneyFactory(user=user3, residence=residence3, campus=campus) 118 + self.assertEquals(Journey.objects.available(kind=GOING).count(), 2) 119 + 120 + def test_available_return_query(self): 121 + # Creates the available journeys with driver... 122 + user1 = UserFactory() 123 + residence1 = ResidenceFactory(user=user1, position=Point(883877.34, 547084.05, srid=DEFAULT_PROJECTED_SRID)) 124 + user2 = UserFactory() 125 + residence2 = ResidenceFactory(user=user2, position=Point(882823.07, 545542.48, srid=DEFAULT_PROJECTED_SRID)) 126 + campus = CampusFactory() 127 + JourneyFactory(user=user1, driver=user1, residence=residence1, campus=campus, kind=RETURN) 128 + JourneyFactory(user=user2, driver=user2, residence=residence2, campus=campus) 129 + # Creates a journey without driver 130 + user3 = UserFactory() 131 + residence3 = ResidenceFactory(user=user3, position=Point(865621.24, 545877.33, srid=DEFAULT_PROJECTED_SRID)) 132 + JourneyFactory(user=user3, residence=residence3, campus=campus, kind=RETURN) 133 + self.assertEquals(Journey.objects.available(kind=RETURN).count(), 1) 134 + 135 + def test_available_query(self): 136 + # Creates the available journeys with driver... 137 + user1 = UserFactory() 138 + residence1 = ResidenceFactory(user=user1, position=Point(883877.34, 547084.05, srid=DEFAULT_PROJECTED_SRID)) 139 + user2 = UserFactory() 140 + residence2 = ResidenceFactory(user=user2, position=Point(882823.07, 545542.48, srid=DEFAULT_PROJECTED_SRID)) 141 + campus = CampusFactory() 142 + JourneyFactory(user=user1, driver=user1, residence=residence1, campus=campus, kind=RETURN) 143 + JourneyFactory(user=user2, driver=user2, residence=residence2, campus=campus) 144 + # Creates a journey without driver 145 + user3 = UserFactory() 146 + residence3 = ResidenceFactory(user=user3, position=Point(865621.24, 545274.90, srid=DEFAULT_PROJECTED_SRID)) 147 + JourneyFactory(user=user3, residence=residence3, campus=campus, kind=RETURN) 148 + self.assertEquals(Journey.objects.available().count(), 2) 149 + 150 + def test_nearby_query(self): 151 + # Creates the available journeys with driver... 152 + user1 = UserFactory() 153 + residence1 = ResidenceFactory(user=user1, position=Point(883877.34, 547084.05, srid=DEFAULT_PROJECTED_SRID)) 154 + user2 = UserFactory() 155 + residence2 = ResidenceFactory(user=user2, position=Point(882823.07, 545542.48, srid=DEFAULT_PROJECTED_SRID)) 156 + campus = CampusFactory() 157 + user3 = UserFactory() 158 + residence3 = ResidenceFactory(user=user3, position=Point(865621.24, 545274.90, srid=DEFAULT_PROJECTED_SRID)) 159 + JourneyFactory(user=user1, driver=user1, residence=residence1, campus=campus) 160 + JourneyFactory(user=user2, driver=user2, residence=residence2, campus=campus) 161 + JourneyFactory(user=user3, driver=user3, residence=residence3, campus=campus) 162 + point = Point(882532.74, 545437.43, srid=DEFAULT_PROJECTED_SRID) 163 + self.assertEquals(Journey.objects.nearby( 164 + geometry=point, 165 + distance=D(m=2500) 166 + ).count(), 2) 167 + 168 + def test_nearby_going_query(self): 169 + # Creates the available journeys with driver... 170 + user1 = UserFactory() 171 + residence1 = ResidenceFactory(user=user1, position=Point(883877.34, 547084.05, srid=DEFAULT_PROJECTED_SRID)) 172 + user2 = UserFactory() 173 + residence2 = ResidenceFactory(user=user2, position=Point(882823.07, 545542.48, srid=DEFAULT_PROJECTED_SRID)) 174 + campus = CampusFactory() 175 + user3 = UserFactory() 176 + residence3 = ResidenceFactory(user=user3, position=Point(865621.24, 545274.90, srid=DEFAULT_PROJECTED_SRID)) 177 + JourneyFactory(user=user1, driver=user1, residence=residence1, campus=campus) 178 + JourneyFactory(user=user2, driver=user2, residence=residence2, campus=campus) 179 + JourneyFactory(user=user3, driver=user3, residence=residence3, campus=campus) 180 + point = Point(882532.74, 545437.43, srid=DEFAULT_PROJECTED_SRID) 181 + self.assertEquals(Journey.objects.nearby( 182 + geometry=point, 183 + distance=D(m=2500), 184 + kind=GOING 185 + ).count(), 2) 186 + 187 + def test_recommended_query(self): 188 + # Creates the available journeys with driver... 189 + user1 = UserFactory() 190 + residence1 = ResidenceFactory(user=user1, position=Point(883877.34, 547084.05, srid=DEFAULT_PROJECTED_SRID)) 191 + user2 = UserFactory() 192 + residence2 = ResidenceFactory(user=user2, position=Point(882823.07, 545542.48, srid=DEFAULT_PROJECTED_SRID)) 193 + campus = CampusFactory() 194 + user3 = UserFactory() 195 + residence3 = ResidenceFactory(user=user3, position=Point(865621.24, 545274.90, srid=DEFAULT_PROJECTED_SRID)) 196 + JourneyFactory(user=user1, driver=user1, residence=residence1, campus=campus) 197 + JourneyFactory(user=user2, driver=user2, residence=residence2, campus=campus) 198 + JourneyFactory(user=user3, driver=user3, residence=residence3, campus=campus) 199 + user4 = UserFactory() 200 + residence4 = ResidenceFactory( 201 + user=user4, position=Point(882532.74, 545437.43, srid=DEFAULT_PROJECTED_SRID), distance=2500 202 + ) 203 + JourneyFactory(user=user4, residence=residence4, campus=campus) 204 + self.assertEquals(Journey.objects.recommended( 205 + user=user4, 206 + ).count(), 2) 207 + 208 + def test_recommended_going_query(self): 209 + # Creates the available journeys with driver... 210 + user1 = UserFactory() 211 + residence1 = ResidenceFactory(user=user1, position=Point(883877.34, 547084.05, srid=DEFAULT_PROJECTED_SRID)) 212 + user2 = UserFactory() 213 + residence2 = ResidenceFactory(user=user2, position=Point(882823.07, 545542.48, srid=DEFAULT_PROJECTED_SRID)) 214 + campus = CampusFactory() 215 + user3 = UserFactory() 216 + residence3 = ResidenceFactory(user=user3, position=Point(865621.24, 545274.90, srid=DEFAULT_PROJECTED_SRID)) 217 + JourneyFactory(user=user1, driver=user1, residence=residence1, campus=campus) 218 + JourneyFactory(user=user2, driver=user2, residence=residence2, campus=campus) 219 + JourneyFactory(user=user3, driver=user3, residence=residence3, campus=campus) 220 + user4 = UserFactory() 221 + residence4 = ResidenceFactory( 222 + user=user4, position=Point(882532.74, 545437.43, srid=DEFAULT_PROJECTED_SRID), distance=2500 223 + ) 224 + JourneyFactory(user=user4, residence=residence4, campus=campus) 225 + self.assertEquals(Journey.objects.recommended( 226 + user=user4, 227 + kind=GOING 228 + ).count(), 2)
+11
upvcarshare/manage.py
··· 1 + #!/usr/bin/env python 2 + # -*- coding: utf-8 -*- 3 + import os 4 + import sys 5 + 6 + if __name__ == "__main__": 7 + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local") 8 + 9 + from django.core.management import execute_from_command_line 10 + 11 + execute_from_command_line(sys.argv)
+62
upvcarshare/static/sass/project.scss
··· 1 + // Import own SCSS files 2 + // ----------------------------------------------------------------------------- 3 + 4 + @import "variables"; 5 + 6 + // Import Bootstrap 7 + // ----------------------------------------------------------------------------- 8 + 9 + @import "bootstrap/scss/bootstrap"; 10 + 11 + // Project specific 12 + // ----------------------------------------------------------------------------- 13 + 14 + // Alert colors 15 + 16 + $white: #fff; 17 + $mint-green: #d6e9c6; 18 + $black: #000; 19 + $pink: #f2dede; 20 + $dark-pink: #eed3d7; 21 + $red: #b94a48; 22 + 23 + // bootstrap alert CSS, translated to the django-standard levels of 24 + // debug, info, success, warning, error 25 + 26 + .alert-debug { 27 + background-color: $white; 28 + border-color: $mint-green; 29 + color: $black; 30 + } 31 + 32 + .alert-error { 33 + background-color: $pink; 34 + border-color: $dark-pink; 35 + color: $red; 36 + } 37 + 38 + // This is a fix for the bootstrap4 alpha release 39 + 40 + @media (max-width: 47.9em) { 41 + .navbar-nav .nav-item { 42 + display: inline-block; 43 + float: none; 44 + width: 100%; 45 + } 46 + 47 + .navbar-nav .nav-item + .nav-item { 48 + margin-left: 0; 49 + } 50 + 51 + .nav.navbar-nav.pull-xs-right { 52 + float: none !important; 53 + } 54 + } 55 + 56 + // Display django-debug-toolbar. 57 + // See https://github.com/django-debug-toolbar/django-debug-toolbar/issues/742 58 + // and https://github.com/pydanny/cookiecutter-django/issues/317 59 + 60 + [hidden][style="display: block;"] { 61 + display: block !important; 62 + }
+2
upvcarshare/static/sass/variables.scss
··· 1 + // Options from Bootstrap 2 + $enable-flex: true;
+21
upvcarshare/templates/base.html
··· 1 + {% load static %} 2 + <!DOCTYPE html> 3 + <html lang="en"> 4 + <head> 5 + <!-- Required meta tags always come first --> 6 + <meta charset="utf-8"> 7 + <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> 8 + <meta http-equiv="x-ua-compatible" content="ie=edge"> 9 + 10 + <!-- Bootstrap CSS --> 11 + <link rel="stylesheet" href="{% static "css/bundle.css" %}"> 12 + </head> 13 + <body> 14 + {% block body %} 15 + {% endblock body %} 16 + <!-- jQuery first, then Bootstrap JS. --> 17 + <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> 18 + <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.2/js/bootstrap.min.js" integrity="sha384-vZ2WRJMwsjRMW/8U7i6PWi6AlO1L79snBrmgiDpgIWJ82z8eA5lenwvxbMV1PAh7" crossorigin="anonymous"></script> 19 + <script src="{% static "js/bundle.js" %}"></script> 20 + </body> 21 + </html>
+2
upvcarshare/users/__init__.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import
+2
upvcarshare/users/api/__init__.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import
+2
upvcarshare/users/api/v1/__init__.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import
+2
upvcarshare/users/api/v1/resources.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import
+8
upvcarshare/users/managers.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import 3 + 4 + from django.contrib.auth.models import UserManager as AuthUserManager 5 + 6 + 7 + class UserManager(AuthUserManager): 8 + pass
+48
upvcarshare/users/migrations/0001_initial.py
··· 1 + # -*- coding: utf-8 -*- 2 + # Generated by Django 1.9.5 on 2016-05-16 13:04 3 + from __future__ import unicode_literals 4 + 5 + import django.contrib.auth.models 6 + import django.contrib.gis.db.models.fields 7 + import django.core.validators 8 + from django.db import migrations, models 9 + import django.utils.timezone 10 + 11 + 12 + class Migration(migrations.Migration): 13 + 14 + initial = True 15 + 16 + dependencies = [ 17 + ('auth', '0007_alter_validators_add_error_messages'), 18 + ] 19 + 20 + operations = [ 21 + migrations.CreateModel( 22 + name='User', 23 + fields=[ 24 + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 25 + ('password', models.CharField(max_length=128, verbose_name='password')), 26 + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), 27 + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), 28 + ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=30, unique=True, validators=[django.core.validators.RegexValidator('^[\\w.@+-]+$', 'Enter a valid username. This value may contain only letters, numbers and @/./+/-/_ characters.')], verbose_name='username')), 29 + ('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')), 30 + ('last_name', models.CharField(blank=True, max_length=30, verbose_name='last name')), 31 + ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), 32 + ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), 33 + ('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')), 34 + ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), 35 + ('default_address', models.TextField(blank=True, null=True)), 36 + ('default_position', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=2062)), 37 + ('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')), 38 + ('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')), 39 + ], 40 + options={ 41 + 'verbose_name': 'user', 42 + 'verbose_name_plural': 'users', 43 + }, 44 + managers=[ 45 + ('objects', django.contrib.auth.models.UserManager()), 46 + ], 47 + ), 48 + ]
upvcarshare/users/migrations/__init__.py

This is a binary file and will not be displayed.

+30
upvcarshare/users/models.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import 3 + 4 + from django.contrib.auth.base_user import AbstractBaseUser 5 + from django.contrib.auth.models import PermissionsMixin, AbstractUser, UserManager 6 + from django.contrib.gis.db import models 7 + from django.utils.translation import ugettext_lazy as _ 8 + from rest_framework.authtoken.models import Token 9 + 10 + from journeys import DEFAULT_PROJECTED_SRID 11 + 12 + 13 + class User(AbstractUser): 14 + """Custom user model.""" 15 + default_address = models.TextField(null=True, blank=True) 16 + default_position = models.PointField(null=True, blank=True, srid=DEFAULT_PROJECTED_SRID) 17 + 18 + objects = UserManager() 19 + 20 + class Meta: 21 + verbose_name = _('user') 22 + verbose_name_plural = _('users') 23 + 24 + def save(self, *args, **kwargs): 25 + """Override to create API Token.""" 26 + created = self.pk is None 27 + result = super(User, self).save(*args, **kwargs) 28 + if created: 29 + Token.objects.create(user=self) 30 + return result
+2
upvcarshare/users/tests/__init__.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import
+12
upvcarshare/users/tests/factories.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import 3 + 4 + import factory 5 + 6 + 7 + class UserFactory(factory.django.DjangoModelFactory): 8 + 9 + username = factory.Sequence(lambda n: 'foo%s' % n) 10 + 11 + class Meta: 12 + model = "users.User"
+2
upvcarshare/users/tests/test_models.py
··· 1 + # -*- coding: utf-8 -*- 2 + from __future__ import unicode_literals, print_function, absolute_import