this repo has no description
0
fork

Configure Feed

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

Init commit. <3

biswaz 9be04171

+3392
+5
.coveragerc
··· 1 + [run] 2 + include = care/* 3 + omit = *migrations*, *tests* 4 + plugins = 5 + django_coverage_plugin
+39
.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 = 88 17 + known_first_party = care,config 18 + multi_line_output = 3 19 + default_section = THIRDPARTY 20 + recursive = true 21 + skip = venv/ 22 + skip_glob = **/migrations/*.py 23 + include_trailing_comma = true 24 + force_grid_wrap = 0 25 + use_parentheses = true 26 + 27 + [*.{html,css,scss,json,yml}] 28 + indent_style = space 29 + indent_size = 2 30 + 31 + [*.md] 32 + trim_trailing_whitespace = false 33 + 34 + [Makefile] 35 + indent_style = tab 36 + 37 + [nginx.conf] 38 + indent_style = space 39 + indent_size = 2
+4
.envs/.local/.django
··· 1 + # General 2 + # ------------------------------------------------------------------------------ 3 + USE_DOCKER=yes 4 + IPYTHONDIR=/app/.ipython
+7
.envs/.local/.postgres
··· 1 + # PostgreSQL 2 + # ------------------------------------------------------------------------------ 3 + POSTGRES_HOST=postgres 4 + POSTGRES_PORT=5432 5 + POSTGRES_DB=care 6 + POSTGRES_USER=tqSuxePMRMcDduwVCzTnCEbqWfroNvcz 7 + POSTGRES_PASSWORD=JDUQbjXh0jmzK6tk5gWsK04PQvBXP6t7cIkuxyqBAB5JbZxtWSy5DMmOAv1Fn2jO
+1
.gitattributes
··· 1 + * text=auto
+344
.gitignore
··· 1 + ### Python template 2 + # Byte-compiled / optimized / DLL files 3 + __pycache__/ 4 + *.py[cod] 5 + *$py.class 6 + 7 + # C extensions 8 + *.so 9 + 10 + # Distribution / packaging 11 + .Python 12 + build/ 13 + develop-eggs/ 14 + dist/ 15 + downloads/ 16 + eggs/ 17 + .eggs/ 18 + lib/ 19 + lib64/ 20 + parts/ 21 + sdist/ 22 + var/ 23 + wheels/ 24 + *.egg-info/ 25 + .installed.cfg 26 + *.egg 27 + 28 + # PyInstaller 29 + # Usually these files are written by a python script from a template 30 + # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 + *.manifest 32 + *.spec 33 + 34 + # Installer logs 35 + pip-log.txt 36 + pip-delete-this-directory.txt 37 + 38 + # Unit test / coverage reports 39 + htmlcov/ 40 + .tox/ 41 + .coverage 42 + .coverage.* 43 + .cache 44 + nosetests.xml 45 + coverage.xml 46 + *.cover 47 + .hypothesis/ 48 + 49 + # Translations 50 + *.mo 51 + *.pot 52 + 53 + # Django stuff: 54 + staticfiles/ 55 + 56 + # Sphinx documentation 57 + docs/_build/ 58 + 59 + # PyBuilder 60 + target/ 61 + 62 + # pyenv 63 + .python-version 64 + 65 + 66 + 67 + # Environments 68 + .venv 69 + venv/ 70 + ENV/ 71 + 72 + # Rope project settings 73 + .ropeproject 74 + 75 + # mkdocs documentation 76 + /site 77 + 78 + # mypy 79 + .mypy_cache/ 80 + 81 + 82 + ### Node template 83 + # Logs 84 + logs 85 + *.log 86 + npm-debug.log* 87 + yarn-debug.log* 88 + yarn-error.log* 89 + 90 + # Runtime data 91 + pids 92 + *.pid 93 + *.seed 94 + *.pid.lock 95 + 96 + # Directory for instrumented libs generated by jscoverage/JSCover 97 + lib-cov 98 + 99 + # Coverage directory used by tools like istanbul 100 + coverage 101 + 102 + # nyc test coverage 103 + .nyc_output 104 + 105 + # Bower dependency directory (https://bower.io/) 106 + bower_components 107 + 108 + # node-waf configuration 109 + .lock-wscript 110 + 111 + # Compiled binary addons (http://nodejs.org/api/addons.html) 112 + build/Release 113 + 114 + # Dependency directories 115 + node_modules/ 116 + jspm_packages/ 117 + 118 + # Typescript v1 declaration files 119 + typings/ 120 + 121 + # Optional npm cache directory 122 + .npm 123 + 124 + # Optional eslint cache 125 + .eslintcache 126 + 127 + # Optional REPL history 128 + .node_repl_history 129 + 130 + # Output of 'npm pack' 131 + *.tgz 132 + 133 + # Yarn Integrity file 134 + .yarn-integrity 135 + 136 + 137 + ### Linux template 138 + *~ 139 + 140 + # temporary files which can be created if a process still has a handle open of a deleted file 141 + .fuse_hidden* 142 + 143 + # KDE directory preferences 144 + .directory 145 + 146 + # Linux trash folder which might appear on any partition or disk 147 + .Trash-* 148 + 149 + # .nfs files are created when an open file is removed but is still being accessed 150 + .nfs* 151 + 152 + 153 + ### VisualStudioCode template 154 + .vscode/* 155 + !.vscode/settings.json 156 + !.vscode/tasks.json 157 + !.vscode/launch.json 158 + !.vscode/extensions.json 159 + 160 + 161 + # Provided default Pycharm Run/Debug Configurations should be tracked by git 162 + # In case of local modifications made by Pycharm, use update-index command 163 + # for each changed file, like this: 164 + # git update-index --assume-unchanged .idea/care.iml 165 + ### JetBrains template 166 + # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 167 + # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 168 + 169 + # User-specific stuff: 170 + .idea/**/workspace.xml 171 + .idea/**/tasks.xml 172 + .idea/dictionaries 173 + 174 + # Sensitive or high-churn files: 175 + .idea/**/dataSources/ 176 + .idea/**/dataSources.ids 177 + .idea/**/dataSources.xml 178 + .idea/**/dataSources.local.xml 179 + .idea/**/sqlDataSources.xml 180 + .idea/**/dynamic.xml 181 + .idea/**/uiDesigner.xml 182 + 183 + # Gradle: 184 + .idea/**/gradle.xml 185 + .idea/**/libraries 186 + 187 + # CMake 188 + cmake-build-debug/ 189 + 190 + # Mongo Explorer plugin: 191 + .idea/**/mongoSettings.xml 192 + 193 + ## File-based project format: 194 + *.iws 195 + 196 + ## Plugin-specific files: 197 + 198 + # IntelliJ 199 + out/ 200 + 201 + # mpeltonen/sbt-idea plugin 202 + .idea_modules/ 203 + 204 + # JIRA plugin 205 + atlassian-ide-plugin.xml 206 + 207 + # Cursive Clojure plugin 208 + .idea/replstate.xml 209 + 210 + # Crashlytics plugin (for Android Studio and IntelliJ) 211 + com_crashlytics_export_strings.xml 212 + crashlytics.properties 213 + crashlytics-build.properties 214 + fabric.properties 215 + 216 + 217 + 218 + ### Windows template 219 + # Windows thumbnail cache files 220 + Thumbs.db 221 + ehthumbs.db 222 + ehthumbs_vista.db 223 + 224 + # Dump file 225 + *.stackdump 226 + 227 + # Folder config file 228 + Desktop.ini 229 + 230 + # Recycle Bin used on file shares 231 + $RECYCLE.BIN/ 232 + 233 + # Windows Installer files 234 + *.cab 235 + *.msi 236 + *.msm 237 + *.msp 238 + 239 + # Windows shortcuts 240 + *.lnk 241 + 242 + 243 + ### macOS template 244 + # General 245 + *.DS_Store 246 + .AppleDouble 247 + .LSOverride 248 + 249 + # Icon must end with two \r 250 + Icon 251 + 252 + # Thumbnails 253 + ._* 254 + 255 + # Files that might appear in the root of a volume 256 + .DocumentRevisions-V100 257 + .fseventsd 258 + .Spotlight-V100 259 + .TemporaryItems 260 + .Trashes 261 + .VolumeIcon.icns 262 + .com.apple.timemachine.donotpresent 263 + 264 + # Directories potentially created on remote AFP share 265 + .AppleDB 266 + .AppleDesktop 267 + Network Trash Folder 268 + Temporary Items 269 + .apdisk 270 + 271 + 272 + ### SublimeText template 273 + # Cache files for Sublime Text 274 + *.tmlanguage.cache 275 + *.tmPreferences.cache 276 + *.stTheme.cache 277 + 278 + # Workspace files are user-specific 279 + *.sublime-workspace 280 + 281 + # Project files should be checked into the repository, unless a significant 282 + # proportion of contributors will probably not be using Sublime Text 283 + # *.sublime-project 284 + 285 + # SFTP configuration file 286 + sftp-config.json 287 + 288 + # Package control specific files 289 + Package Control.last-run 290 + Package Control.ca-list 291 + Package Control.ca-bundle 292 + Package Control.system-ca-bundle 293 + Package Control.cache/ 294 + Package Control.ca-certs/ 295 + Package Control.merged-ca-bundle 296 + Package Control.user-ca-bundle 297 + oscrypto-ca-bundle.crt 298 + bh_unicode_properties.cache 299 + 300 + # Sublime-github package stores a github token in this file 301 + # https://packagecontrol.io/packages/sublime-github 302 + GitHub.sublime-settings 303 + 304 + 305 + ### Vim template 306 + # Swap 307 + [._]*.s[a-v][a-z] 308 + [._]*.sw[a-p] 309 + [._]s[a-v][a-z] 310 + [._]sw[a-p] 311 + 312 + # Session 313 + Session.vim 314 + 315 + # Temporary 316 + .netrwhist 317 + 318 + # Auto-generated tag files 319 + tags 320 + 321 + 322 + ### VirtualEnv template 323 + # Virtualenv 324 + [Bb]in 325 + [Ii]nclude 326 + [Ll]ib 327 + [Ll]ib64 328 + [Ss]cripts 329 + pyvenv.cfg 330 + pip-selfcheck.json 331 + .env 332 + 333 + 334 + ### Project template 335 + 336 + MailHog 337 + care/media/ 338 + 339 + .pytest_cache/ 340 + 341 + 342 + .env 343 + .envs/* 344 + !.envs/.local/
+43
.idea/care.iml
··· 1 + <?xml version="1.0" encoding="UTF-8"?> 2 + <module type="PYTHON_MODULE" version="4"> 3 + <component name="FacetManager"> 4 + <facet type="django" name="Django"> 5 + <configuration> 6 + <option name="rootFolder" value="$MODULE_DIR$" /> 7 + <option name="settingsModule" value="config/settings/local.py" /> 8 + <option name="manageScript" value="$MODULE_DIR$/manage.py" /> 9 + <option name="environment" value="&lt;map/&gt;" /> 10 + <option name="doNotUseTestRunner" value="false" /> 11 + <option name="trackFilePattern" value="migrations" /> 12 + </configuration> 13 + </facet> 14 + </component> 15 + <component name="NewModuleRootManager"> 16 + 17 + <content url="file://$MODULE_DIR$" /> 18 + 19 + <orderEntry type="sourceFolder" forTests="false" /> 20 + </component> 21 + <component name="PackageRequirementsSettings"> 22 + <option name="requirementsPath" value="$MODULE_DIR$/requirements/local.txt" /> 23 + </component> 24 + <component name="PyDocumentationSettings"> 25 + <option name="renderExternalDocumentation" value="true" /> 26 + </component> 27 + <component name="ReSTService"> 28 + <option name="workdir" value="$MODULE_DIR$/docs" /> 29 + <option name="DOC_DIR" value="$MODULE_DIR$/docs" /> 30 + </component> 31 + <component name="TemplatesService"> 32 + <option name="TEMPLATE_CONFIGURATION" value="Django" /> 33 + <option name="TEMPLATE_FOLDERS"> 34 + <list> 35 + <option value="$MODULE_DIR$/care/templates" /> 36 + </list> 37 + </option> 38 + </component> 39 + <component name="TestRunnerService"> 40 + <option name="projectConfiguration" value="pytest" /> 41 + <option name="PROJECT_TEST_RUNNER" value="pytest" /> 42 + </component> 43 + </module>
+6
.idea/misc.xml
··· 1 + <?xml version="1.0" encoding="UTF-8"?> 2 + <project version="4"> 3 + <component name="JavaScriptSettings"> 4 + <option name="languageLevel" value="ES6" /> 5 + </component> 6 + </project>
+8
.idea/modules.xml
··· 1 + <?xml version="1.0" encoding="UTF-8"?> 2 + <project version="4"> 3 + <component name="ProjectModuleManager"> 4 + <modules> 5 + <module fileurl="file://$PROJECT_DIR$/.idea/care.iml" filepath="$PROJECT_DIR$/.idea/care.iml" /> 6 + </modules> 7 + </component> 8 + </project>
+21
.idea/runConfigurations/merge_production_dotenvs_in_dotenv.xml
··· 1 + <component name="ProjectRunConfigurationManager"> 2 + <configuration default="false" name="merge_production_dotenvs_in_dotenv" type="PythonConfigurationType" factoryName="Python" singleton="true"> 3 + <module name="care" /> 4 + <option name="INTERPRETER_OPTIONS" value="" /> 5 + <option name="PARENT_ENVS" value="true" /> 6 + <envs> 7 + <env name="PYTHONUNBUFFERED" value="1" /> 8 + </envs> 9 + <option name="SDK_HOME" value="" /> 10 + <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" /> 11 + <option name="IS_MODULE_SDK" value="true" /> 12 + <option name="ADD_CONTENT_ROOTS" value="true" /> 13 + <option name="ADD_SOURCE_ROOTS" value="true" /> 14 + <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" /> 15 + <option name="SCRIPT_NAME" value="merge_production_dotenvs_in_dotenv.py" /> 16 + <option name="PARAMETERS" value="" /> 17 + <option name="SHOW_COMMAND_LINE" value="false" /> 18 + <option name="EMULATE_TERMINAL" value="false" /> 19 + <method /> 20 + </configuration> 21 + </component>
+32
.idea/runConfigurations/migrate.xml
··· 1 + <component name="ProjectRunConfigurationManager"> 2 + <configuration default="false" name="migrate" type="Python.DjangoServer" factoryName="Django server" singleton="true"> 3 + <module name="care" /> 4 + <option name="INTERPRETER_OPTIONS" value="" /> 5 + <option name="PARENT_ENVS" value="true" /> 6 + <envs> 7 + <env name="PYTHONUNBUFFERED" value="1" /> 8 + <env name="DJANGO_SETTINGS_MODULE" value="config.settings.local" /> 9 + </envs> 10 + <option name="SDK_HOME" value="" /> 11 + <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" /> 12 + <option name="IS_MODULE_SDK" value="true" /> 13 + <option name="ADD_CONTENT_ROOTS" value="true" /> 14 + <option name="ADD_SOURCE_ROOTS" value="true" /> 15 + <PathMappingSettings> 16 + <option name="pathMappings"> 17 + <list> 18 + <mapping local-root="$PROJECT_DIR$" remote-root="/app" /> 19 + </list> 20 + </option> 21 + </PathMappingSettings> 22 + <option name="launchJavascriptDebuger" value="false" /> 23 + <option name="host" value="" /> 24 + <option name="additionalOptions" value="" /> 25 + <option name="browserUrl" value="" /> 26 + <option name="runTestServer" value="false" /> 27 + <option name="runNoReload" value="false" /> 28 + <option name="useCustomRunCommand" value="true" /> 29 + <option name="customRunCommand" value="migrate" /> 30 + <method /> 31 + </configuration> 32 + </component>
+25
.idea/runConfigurations/pytest___.xml
··· 1 + <component name="ProjectRunConfigurationManager"> 2 + <configuration default="false" name="pytest: ." type="tests" factoryName="py.test" singleton="true"> 3 + <module name="care" /> 4 + <option name="INTERPRETER_OPTIONS" value="" /> 5 + <option name="PARENT_ENVS" value="true" /> 6 + <option name="SDK_HOME" value="" /> 7 + <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" /> 8 + <option name="IS_MODULE_SDK" value="true" /> 9 + <option name="ADD_CONTENT_ROOTS" value="true" /> 10 + <option name="ADD_SOURCE_ROOTS" value="true" /> 11 + <EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" /> 12 + <PathMappingSettings> 13 + <option name="pathMappings"> 14 + <list> 15 + <mapping local-root="$PROJECT_DIR$" remote-root="/app" /> 16 + </list> 17 + </option> 18 + </PathMappingSettings> 19 + <option name="_new_keywords" value="&quot;&quot;" /> 20 + <option name="_new_additionalArguments" value="&quot;&quot;" /> 21 + <option name="_new_target" value="&quot;.&quot;" /> 22 + <option name="_new_targetType" value="&quot;PATH&quot;" /> 23 + <method /> 24 + </configuration> 25 + </component>
+25
.idea/runConfigurations/pytest__users.xml
··· 1 + <component name="ProjectRunConfigurationManager"> 2 + <configuration default="false" name="pytest: users" type="tests" factoryName="py.test" singleton="true"> 3 + <module name="care" /> 4 + <option name="INTERPRETER_OPTIONS" value="" /> 5 + <option name="PARENT_ENVS" value="true" /> 6 + <option name="SDK_HOME" value="" /> 7 + <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" /> 8 + <option name="IS_MODULE_SDK" value="true" /> 9 + <option name="ADD_CONTENT_ROOTS" value="true" /> 10 + <option name="ADD_SOURCE_ROOTS" value="true" /> 11 + <EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" /> 12 + <PathMappingSettings> 13 + <option name="pathMappings"> 14 + <list> 15 + <mapping local-root="$PROJECT_DIR$" remote-root="/app" /> 16 + </list> 17 + </option> 18 + </PathMappingSettings> 19 + <option name="_new_keywords" value="&quot;&quot;" /> 20 + <option name="_new_additionalArguments" value="&quot;&quot;" /> 21 + <option name="_new_target" value="&quot;./care/users/&quot;" /> 22 + <option name="_new_targetType" value="&quot;PATH&quot;" /> 23 + <method /> 24 + </configuration> 25 + </component>
+33
.idea/runConfigurations/runserver.xml
··· 1 + <component name="ProjectRunConfigurationManager"> 2 + <configuration default="false" name="runserver" type="Python.DjangoServer" factoryName="Django server" singleton="true"> 3 + <module name="care" /> 4 + <option name="INTERPRETER_OPTIONS" value="" /> 5 + <option name="PARENT_ENVS" value="true" /> 6 + <envs> 7 + <env name="PYTHONUNBUFFERED" value="1" /> 8 + <env name="DJANGO_SETTINGS_MODULE" value="config.settings.local" /> 9 + </envs> 10 + <option name="SDK_HOME" value="" /> 11 + <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" /> 12 + <option name="IS_MODULE_SDK" value="true" /> 13 + <option name="ADD_CONTENT_ROOTS" value="true" /> 14 + <option name="ADD_SOURCE_ROOTS" value="true" /> 15 + <PathMappingSettings> 16 + <option name="pathMappings"> 17 + <list> 18 + <mapping local-root="$PROJECT_DIR$" remote-root="/app" /> 19 + </list> 20 + </option> 21 + </PathMappingSettings> 22 + <option name="launchJavascriptDebuger" value="false" /> 23 + <option name="port" value="8000" /> 24 + <option name="host" value="0.0.0.0" /> 25 + <option name="additionalOptions" value="" /> 26 + <option name="browserUrl" value="" /> 27 + <option name="runTestServer" value="false" /> 28 + <option name="runNoReload" value="false" /> 29 + <option name="useCustomRunCommand" value="false" /> 30 + <option name="customRunCommand" value="" /> 31 + <method /> 32 + </configuration> 33 + </component>
+33
.idea/runConfigurations/runserver_plus.xml
··· 1 + <component name="ProjectRunConfigurationManager"> 2 + <configuration default="false" name="runserver_plus" type="Python.DjangoServer" factoryName="Django server" singleton="true"> 3 + <module name="care" /> 4 + <option name="INTERPRETER_OPTIONS" value="" /> 5 + <option name="PARENT_ENVS" value="true" /> 6 + <envs> 7 + <env name="PYTHONUNBUFFERED" value="1" /> 8 + <env name="DJANGO_SETTINGS_MODULE" value="config.settings.local" /> 9 + </envs> 10 + <option name="SDK_HOME" value="" /> 11 + <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" /> 12 + <option name="IS_MODULE_SDK" value="true" /> 13 + <option name="ADD_CONTENT_ROOTS" value="true" /> 14 + <option name="ADD_SOURCE_ROOTS" value="true" /> 15 + <PathMappingSettings> 16 + <option name="pathMappings"> 17 + <list> 18 + <mapping local-root="$PROJECT_DIR$" remote-root="/app" /> 19 + </list> 20 + </option> 21 + </PathMappingSettings> 22 + <option name="launchJavascriptDebuger" value="false" /> 23 + <option name="port" value="8000" /> 24 + <option name="host" value="0.0.0.0" /> 25 + <option name="additionalOptions" value="" /> 26 + <option name="browserUrl" value="" /> 27 + <option name="runTestServer" value="false" /> 28 + <option name="runNoReload" value="false" /> 29 + <option name="useCustomRunCommand" value="true" /> 30 + <option name="customRunCommand" value="runserver_plus" /> 31 + <method /> 32 + </configuration> 33 + </component>
+6
.idea/vcs.xml
··· 1 + <?xml version="1.0" encoding="UTF-8"?> 2 + <project version="4"> 3 + <component name="VcsDirectoryMappings"> 4 + <mapping directory="$PROJECT_DIR$" vcs="Git" /> 5 + </component> 6 + </project>
+14
.idea/webResources.xml
··· 1 + <?xml version="1.0" encoding="UTF-8"?> 2 + <project version="4"> 3 + <component name="WebResourcesPaths"> 4 + <contentEntries> 5 + <entry url="file://$PROJECT_DIR$"> 6 + <entryData> 7 + <resourceRoots> 8 + <path value="file://$PROJECT_DIR$/care/static" /> 9 + </resourceRoots> 10 + </entryData> 11 + </entry> 12 + </contentEntries> 13 + </component> 14 + </project>
+20
.pre-commit-config.yaml
··· 1 + exclude: 'docs|node_modules|migrations|.git|.tox' 2 + default_stages: [commit] 3 + fail_fast: true 4 + 5 + repos: 6 + - repo: https://github.com/pre-commit/pre-commit-hooks 7 + rev: master 8 + hooks: 9 + - id: trailing-whitespace 10 + files: (^|/)a/.+\.(py|html|sh|css|js)$ 11 + 12 + - repo: local 13 + hooks: 14 + - id: flake8 15 + name: flake8 16 + entry: flake8 17 + language: python 18 + types: [python] 19 + args: ['--config=setup.cfg'] 20 +
+14
.pylintrc
··· 1 + [MASTER] 2 + load-plugins=pylint_django 3 + 4 + [FORMAT] 5 + max-line-length=120 6 + 7 + [MESSAGES CONTROL] 8 + disable=missing-docstring,invalid-name 9 + 10 + [DESIGN] 11 + max-parents=13 12 + 13 + [TYPECHECK] 14 + generated-members=REQUEST,acl_users,aq_parent,"[a-zA-Z]+_set{1,2}",save,delete
+1
CONTRIBUTORS.txt
··· 1 + 👪
+10
LICENSE
··· 1 + 2 + The MIT License (MIT) 3 + Copyright (c) 2020, 👪 4 + 5 + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 + 7 + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 + 9 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 +
+3
Procfile
··· 1 + release: python manage.py migrate 2 + web: gunicorn config.wsgi:application 3 +
+126
README.rst
··· 1 + Care 2 + ==== 3 + 4 + corona care center management app for govt of kerala 5 + 6 + .. image:: https://img.shields.io/badge/built%20with-Cookiecutter%20Django-ff69b4.svg 7 + :target: https://github.com/pydanny/cookiecutter-django/ 8 + :alt: Built with Cookiecutter Django 9 + .. image:: https://img.shields.io/badge/code%20style-black-000000.svg 10 + :target: https://github.com/ambv/black 11 + :alt: Black code style 12 + 13 + 14 + :License: MIT 15 + 16 + 17 + Settings 18 + -------- 19 + 20 + Moved to settings_. 21 + 22 + .. _settings: http://cookiecutter-django.readthedocs.io/en/latest/settings.html 23 + 24 + Basic Commands 25 + -------------- 26 + 27 + Setting Up Your Users 28 + ^^^^^^^^^^^^^^^^^^^^^ 29 + 30 + * To create a **normal user account**, just go to Sign Up and fill out the form. Once you submit it, you'll see a "Verify Your E-mail Address" page. Go to your console to see a simulated email verification message. Copy the link into your browser. Now the user's email should be verified and ready to go. 31 + 32 + * To create an **superuser account**, use this command:: 33 + 34 + $ python manage.py createsuperuser 35 + 36 + For convenience, you can keep your normal user logged in on Chrome and your superuser logged in on Firefox (or similar), so that you can see how the site behaves for both kinds of users. 37 + 38 + Type checks 39 + ^^^^^^^^^^^ 40 + 41 + Running type checks with mypy: 42 + 43 + :: 44 + 45 + $ mypy care 46 + 47 + Test coverage 48 + ^^^^^^^^^^^^^ 49 + 50 + To run the tests, check your test coverage, and generate an HTML coverage report:: 51 + 52 + $ coverage run -m pytest 53 + $ coverage html 54 + $ open htmlcov/index.html 55 + 56 + Running tests with py.test 57 + ~~~~~~~~~~~~~~~~~~~~~~~~~~ 58 + 59 + :: 60 + 61 + $ pytest 62 + 63 + Live reloading and Sass CSS compilation 64 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 65 + 66 + Moved to `Live reloading and SASS compilation`_. 67 + 68 + .. _`Live reloading and SASS compilation`: http://cookiecutter-django.readthedocs.io/en/latest/live-reloading-and-sass-compilation.html 69 + 70 + 71 + 72 + 73 + Email Server 74 + ^^^^^^^^^^^^ 75 + 76 + In development, it is often nice to be able to see emails that are being sent from your application. If you choose to use `MailHog`_ when generating the project a local SMTP server with a web interface will be available. 77 + 78 + #. `Download the latest MailHog release`_ for your OS. 79 + 80 + #. Rename the build to ``MailHog``. 81 + 82 + #. Copy the file to the project root. 83 + 84 + #. Make it executable: :: 85 + 86 + $ chmod +x MailHog 87 + 88 + #. Spin up another terminal window and start it there: :: 89 + 90 + ./MailHog 91 + 92 + #. Check out `<http://127.0.0.1:8025/>`_ to see how it goes. 93 + 94 + Now you have your own mail server running locally, ready to receive whatever you send it. 95 + 96 + .. _`Download the latest MailHog release`: https://github.com/mailhog/MailHog/releases 97 + 98 + .. _mailhog: https://github.com/mailhog/MailHog 99 + 100 + 101 + 102 + Sentry 103 + ^^^^^^ 104 + 105 + Sentry is an error logging aggregator service. You can sign up for a free account at https://sentry.io/signup/?code=cookiecutter or download and host it yourself. 106 + The system is setup with reasonable defaults, including 404 logging and integration with the WSGI application. 107 + 108 + You must set the DSN url in production. 109 + 110 + 111 + Deployment 112 + ---------- 113 + 114 + The following details how to deploy this application. 115 + 116 + 117 + Heroku 118 + ^^^^^^ 119 + 120 + See detailed `cookiecutter-django Heroku documentation`_. 121 + 122 + .. _`cookiecutter-django Heroku documentation`: http://cookiecutter-django.readthedocs.io/en/latest/deployment-on-heroku.html 123 + 124 + 125 + 126 +
+7
care/__init__.py
··· 1 + __version__ = "0.1.0" 2 + __version_info__ = tuple( 3 + [ 4 + int(num) if num.isdigit() else num 5 + for num in __version__.replace("-", ".", 1).split(".") 6 + ] 7 + )
+20
care/conftest.py
··· 1 + import pytest 2 + from django.test import RequestFactory 3 + 4 + from care.users.models import User 5 + from care.users.tests.factories import UserFactory 6 + 7 + 8 + @pytest.fixture(autouse=True) 9 + def media_storage(settings, tmpdir): 10 + settings.MEDIA_ROOT = tmpdir.strpath 11 + 12 + 13 + @pytest.fixture 14 + def user() -> User: 15 + return UserFactory() 16 + 17 + 18 + @pytest.fixture 19 + def request_factory() -> RequestFactory: 20 + return RequestFactory()
+5
care/contrib/__init__.py
··· 1 + """ 2 + To understand why this file is here, please read: 3 + 4 + http://cookiecutter-django.readthedocs.io/en/latest/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django 5 + """
+5
care/contrib/sites/__init__.py
··· 1 + """ 2 + To understand why this file is here, please read: 3 + 4 + http://cookiecutter-django.readthedocs.io/en/latest/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django 5 + """
+42
care/contrib/sites/migrations/0001_initial.py
··· 1 + import django.contrib.sites.models 2 + from django.contrib.sites.models import _simple_domain_name_validator 3 + from django.db import migrations, models 4 + 5 + 6 + class Migration(migrations.Migration): 7 + 8 + dependencies = [] 9 + 10 + operations = [ 11 + migrations.CreateModel( 12 + name="Site", 13 + fields=[ 14 + ( 15 + "id", 16 + models.AutoField( 17 + verbose_name="ID", 18 + serialize=False, 19 + auto_created=True, 20 + primary_key=True, 21 + ), 22 + ), 23 + ( 24 + "domain", 25 + models.CharField( 26 + max_length=100, 27 + verbose_name="domain name", 28 + validators=[_simple_domain_name_validator], 29 + ), 30 + ), 31 + ("name", models.CharField(max_length=50, verbose_name="display name")), 32 + ], 33 + options={ 34 + "ordering": ("domain",), 35 + "db_table": "django_site", 36 + "verbose_name": "site", 37 + "verbose_name_plural": "sites", 38 + }, 39 + bases=(models.Model,), 40 + managers=[("objects", django.contrib.sites.models.SiteManager())], 41 + ) 42 + ]
+20
care/contrib/sites/migrations/0002_alter_domain_unique.py
··· 1 + import django.contrib.sites.models 2 + from django.db import migrations, models 3 + 4 + 5 + class Migration(migrations.Migration): 6 + 7 + dependencies = [("sites", "0001_initial")] 8 + 9 + operations = [ 10 + migrations.AlterField( 11 + model_name="site", 12 + name="domain", 13 + field=models.CharField( 14 + max_length=100, 15 + unique=True, 16 + validators=[django.contrib.sites.models._simple_domain_name_validator], 17 + verbose_name="domain name", 18 + ), 19 + ) 20 + ]
+34
care/contrib/sites/migrations/0003_set_site_domain_and_name.py
··· 1 + """ 2 + To understand why this file is here, please read: 3 + 4 + http://cookiecutter-django.readthedocs.io/en/latest/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django 5 + """ 6 + from django.conf import settings 7 + from django.db import migrations 8 + 9 + 10 + def update_site_forward(apps, schema_editor): 11 + """Set site domain and name.""" 12 + Site = apps.get_model("sites", "Site") 13 + Site.objects.update_or_create( 14 + id=settings.SITE_ID, 15 + defaults={ 16 + "domain": "coronasafe.in", 17 + "name": "Care", 18 + }, 19 + ) 20 + 21 + 22 + def update_site_backward(apps, schema_editor): 23 + """Revert site domain and name to default.""" 24 + Site = apps.get_model("sites", "Site") 25 + Site.objects.update_or_create( 26 + id=settings.SITE_ID, defaults={"domain": "example.com", "name": "example.com"} 27 + ) 28 + 29 + 30 + class Migration(migrations.Migration): 31 + 32 + dependencies = [("sites", "0002_alter_domain_unique")] 33 + 34 + operations = [migrations.RunPython(update_site_forward, update_site_backward)]
+5
care/contrib/sites/migrations/__init__.py
··· 1 + """ 2 + To understand why this file is here, please read: 3 + 4 + http://cookiecutter-django.readthedocs.io/en/latest/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django 5 + """
+13
care/static/css/project.css
··· 1 + /* These styles are generated from project.scss. */ 2 + 3 + .alert-debug { 4 + color: black; 5 + background-color: white; 6 + border-color: #d6e9c6; 7 + } 8 + 9 + .alert-error { 10 + color: #b94a48; 11 + background-color: #f2dede; 12 + border-color: #eed3d7; 13 + }
care/static/fonts/.gitkeep

This is a binary file and will not be displayed.

care/static/images/favicons/favicon.ico

This is a binary file and will not be displayed.

+1
care/static/js/project.js
··· 1 + /* Project specific Javascript goes here. */
care/static/sass/custom_bootstrap_vars.scss

This is a binary file and will not be displayed.

+37
care/static/sass/project.scss
··· 1 + 2 + 3 + 4 + 5 + // project specific CSS goes here 6 + 7 + //////////////////////////////// 8 + //Variables// 9 + //////////////////////////////// 10 + 11 + // Alert colors 12 + 13 + $white: #fff; 14 + $mint-green: #d6e9c6; 15 + $black: #000; 16 + $pink: #f2dede; 17 + $dark-pink: #eed3d7; 18 + $red: #b94a48; 19 + 20 + //////////////////////////////// 21 + //Alerts// 22 + //////////////////////////////// 23 + 24 + // bootstrap alert CSS, translated to the django-standard levels of 25 + // debug, info, success, warning, error 26 + 27 + .alert-debug { 28 + background-color: $white; 29 + border-color: $mint-green; 30 + color: $black; 31 + } 32 + 33 + .alert-error { 34 + background-color: $pink; 35 + border-color: $dark-pink; 36 + color: $red; 37 + }
+9
care/templates/403.html
··· 1 + {% extends "base.html" %} 2 + 3 + {% block title %}Forbidden (403){% endblock %} 4 + 5 + {% block content %} 6 + <h1>Forbidden (403)</h1> 7 + 8 + <p>CSRF verification failed. Request aborted.</p> 9 + {% endblock content %}
+9
care/templates/404.html
··· 1 + {% extends "base.html" %} 2 + 3 + {% block title %}Page not found{% endblock %} 4 + 5 + {% block content %} 6 + <h1>Page not found</h1> 7 + 8 + <p>This is not the page you were looking for.</p> 9 + {% endblock content %}
+13
care/templates/500.html
··· 1 + {% extends "base.html" %} 2 + 3 + {% block title %}Server Error{% endblock %} 4 + 5 + {% block content %} 6 + <h1>Ooops!!! 500</h1> 7 + 8 + <h3>Looks like something went wrong!</h3> 9 + 10 + <p>We track these errors automatically, but if the problem persists feel free to contact us. In the meantime, try refreshing.</p> 11 + {% endblock content %} 12 + 13 +
+12
care/templates/account/account_inactive.html
··· 1 + {% extends "account/base.html" %} 2 + 3 + {% load i18n %} 4 + 5 + {% block head_title %}{% trans "Account Inactive" %}{% endblock %} 6 + 7 + {% block inner %} 8 + <h1>{% trans "Account Inactive" %}</h1> 9 + 10 + <p>{% trans "This account is inactive." %}</p> 11 + {% endblock %} 12 +
+10
care/templates/account/base.html
··· 1 + {% extends "base.html" %} 2 + {% block title %}{% block head_title %}{% endblock head_title %}{% endblock title %} 3 + 4 + {% block content %} 5 + <div class="row"> 6 + <div class="col-md-6 offset-md-3"> 7 + {% block inner %}{% endblock %} 8 + </div> 9 + </div> 10 + {% endblock %}
+80
care/templates/account/email.html
··· 1 + 2 + {% extends "account/base.html" %} 3 + 4 + {% load i18n %} 5 + {% load crispy_forms_tags %} 6 + 7 + {% block head_title %}{% trans "Account" %}{% endblock %} 8 + 9 + {% block inner %} 10 + <h1>{% trans "E-mail Addresses" %}</h1> 11 + 12 + {% if user.emailaddress_set.all %} 13 + <p>{% trans 'The following e-mail addresses are associated with your account:' %}</p> 14 + 15 + <form action="{% url 'account_email' %}" class="email_list" method="post"> 16 + {% csrf_token %} 17 + <fieldset class="blockLabels"> 18 + 19 + {% for emailaddress in user.emailaddress_set.all %} 20 + <div class="radio"> 21 + <label for="email_radio_{{forloop.counter}}" class="{% if emailaddress.primary %}primary_email{%endif%}"> 22 + 23 + <input id="email_radio_{{forloop.counter}}" type="radio" name="email" {% if emailaddress.primary or user.emailaddress_set.count == 1 %}checked="checked"{%endif %} value="{{emailaddress.email}}"/> 24 + 25 + {{ emailaddress.email }} 26 + {% if emailaddress.verified %} 27 + <span class="verified">{% trans "Verified" %}</span> 28 + {% else %} 29 + <span class="unverified">{% trans "Unverified" %}</span> 30 + {% endif %} 31 + {% if emailaddress.primary %}<span class="primary">{% trans "Primary" %}</span>{% endif %} 32 + </label> 33 + </div> 34 + {% endfor %} 35 + 36 + <div class="form-group"> 37 + <button class="secondaryAction btn btn-primary" type="submit" name="action_primary" >{% trans 'Make Primary' %}</button> 38 + <button class="secondaryAction btn btn-primary" type="submit" name="action_send" >{% trans 'Re-send Verification' %}</button> 39 + <button class="primaryAction btn btn-primary" type="submit" name="action_remove" >{% trans 'Remove' %}</button> 40 + </div> 41 + 42 + </fieldset> 43 + </form> 44 + 45 + {% else %} 46 + <p><strong>{% trans 'Warning:'%}</strong> {% trans "You currently do not have any e-mail address set up. You should really add an e-mail address so you can receive notifications, reset your password, etc." %}</p> 47 + 48 + {% endif %} 49 + 50 + 51 + <h2>{% trans "Add E-mail Address" %}</h2> 52 + 53 + <form method="post" action="{% url 'account_email' %}" class="add_email"> 54 + {% csrf_token %} 55 + {{ form|crispy }} 56 + <button class="btn btn-primary" name="action_add" type="submit">{% trans "Add E-mail" %}</button> 57 + </form> 58 + 59 + {% endblock %} 60 + 61 + 62 + {% block javascript %} 63 + {{ block.super }} 64 + <script type="text/javascript"> 65 + (function() { 66 + var message = "{% trans 'Do you really want to remove the selected e-mail address?' %}"; 67 + var actions = document.getElementsByName('action_remove'); 68 + if (actions.length) { 69 + actions[0].addEventListener("click", function(e) { 70 + if (! confirm(message)) { 71 + e.preventDefault(); 72 + } 73 + }); 74 + } 75 + })(); 76 + 77 + $('.form-group').removeClass('row'); 78 + </script> 79 + {% endblock %} 80 +
+32
care/templates/account/email_confirm.html
··· 1 + {% extends "account/base.html" %} 2 + 3 + {% load i18n %} 4 + {% load account %} 5 + 6 + {% block head_title %}{% trans "Confirm E-mail Address" %}{% endblock %} 7 + 8 + 9 + {% block inner %} 10 + <h1>{% trans "Confirm E-mail Address" %}</h1> 11 + 12 + {% if confirmation %} 13 + 14 + {% user_display confirmation.email_address.user as user_display %} 15 + 16 + <p>{% blocktrans with confirmation.email_address.email as email %}Please confirm that <a href="mailto:{{ email }}">{{ email }}</a> is an e-mail address for user {{ user_display }}.{% endblocktrans %}</p> 17 + 18 + <form method="post" action="{% url 'account_confirm_email' confirmation.key %}"> 19 + {% csrf_token %} 20 + <button class="btn btn-primary" type="submit">{% trans 'Confirm' %}</button> 21 + </form> 22 + 23 + {% else %} 24 + 25 + {% url 'account_email' as email_url %} 26 + 27 + <p>{% blocktrans %}This e-mail confirmation link expired or is invalid. Please <a href="{{ email_url }}">issue a new e-mail confirmation request</a>.{% endblocktrans %}</p> 28 + 29 + {% endif %} 30 + 31 + {% endblock %} 32 +
+48
care/templates/account/login.html
··· 1 + {% extends "account/base.html" %} 2 + 3 + {% load i18n %} 4 + {% load account socialaccount %} 5 + {% load crispy_forms_tags %} 6 + 7 + {% block head_title %}{% trans "Sign In" %}{% endblock %} 8 + 9 + {% block inner %} 10 + 11 + <h1>{% trans "Sign In" %}</h1> 12 + 13 + {% get_providers as socialaccount_providers %} 14 + 15 + {% if socialaccount_providers %} 16 + <p>{% blocktrans with site.name as site_name %}Please sign in with one 17 + of your existing third party accounts. Or, <a href="{{ signup_url }}">sign up</a> 18 + for a {{ site_name }} account and sign in below:{% endblocktrans %}</p> 19 + 20 + <div class="socialaccount_ballot"> 21 + 22 + <ul class="socialaccount_providers"> 23 + {% include "socialaccount/snippets/provider_list.html" with process="login" %} 24 + </ul> 25 + 26 + <div class="login-or">{% trans 'or' %}</div> 27 + 28 + </div> 29 + 30 + {% include "socialaccount/snippets/login_extra.html" %} 31 + 32 + {% else %} 33 + <p>{% blocktrans %}If you have not created an account yet, then please 34 + <a href="{{ signup_url }}">sign up</a> first.{% endblocktrans %}</p> 35 + {% endif %} 36 + 37 + <form class="login" method="POST" action="{% url 'account_login' %}"> 38 + {% csrf_token %} 39 + {{ form|crispy }} 40 + {% if redirect_field_value %} 41 + <input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" /> 42 + {% endif %} 43 + <a class="button secondaryAction" href="{% url 'account_reset_password' %}">{% trans "Forgot Password?" %}</a> 44 + <button class="primaryAction btn btn-primary" type="submit">{% trans "Sign In" %}</button> 45 + </form> 46 + 47 + {% endblock %} 48 +
+22
care/templates/account/logout.html
··· 1 + {% extends "account/base.html" %} 2 + 3 + {% load i18n %} 4 + 5 + {% block head_title %}{% trans "Sign Out" %}{% endblock %} 6 + 7 + {% block inner %} 8 + <h1>{% trans "Sign Out" %}</h1> 9 + 10 + <p>{% trans 'Are you sure you want to sign out?' %}</p> 11 + 12 + <form method="post" action="{% url 'account_logout' %}"> 13 + {% csrf_token %} 14 + {% if redirect_field_value %} 15 + <input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}"/> 16 + {% endif %} 17 + <button class="btn btn-danger" type="submit">{% trans 'Sign Out' %}</button> 18 + </form> 19 + 20 + 21 + {% endblock %} 22 +
+17
care/templates/account/password_change.html
··· 1 + {% extends "account/base.html" %} 2 + 3 + {% load i18n %} 4 + {% load crispy_forms_tags %} 5 + 6 + {% block head_title %}{% trans "Change Password" %}{% endblock %} 7 + 8 + {% block inner %} 9 + <h1>{% trans "Change Password" %}</h1> 10 + 11 + <form method="POST" action="{% url 'account_change_password' %}" class="password_change"> 12 + {% csrf_token %} 13 + {{ form|crispy }} 14 + <button class="btn btn-primary" type="submit" name="action">{% trans "Change Password" %}</button> 15 + </form> 16 + {% endblock %} 17 +
+26
care/templates/account/password_reset.html
··· 1 + {% extends "account/base.html" %} 2 + 3 + {% load i18n %} 4 + {% load account %} 5 + {% load crispy_forms_tags %} 6 + 7 + {% block head_title %}{% trans "Password Reset" %}{% endblock %} 8 + 9 + {% block inner %} 10 + 11 + <h1>{% trans "Password Reset" %}</h1> 12 + {% if user.is_authenticated %} 13 + {% include "account/snippets/already_logged_in.html" %} 14 + {% endif %} 15 + 16 + <p>{% trans "Forgotten your password? Enter your e-mail address below, and we'll send you an e-mail allowing you to reset it." %}</p> 17 + 18 + <form method="POST" action="{% url 'account_reset_password' %}" class="password_reset"> 19 + {% csrf_token %} 20 + {{ form|crispy }} 21 + <input class="btn btn-primary" type="submit" value="{% trans 'Reset My Password' %}" /> 22 + </form> 23 + 24 + <p>{% blocktrans %}Please contact us if you have any trouble resetting your password.{% endblocktrans %}</p> 25 + {% endblock %} 26 +
+17
care/templates/account/password_reset_done.html
··· 1 + {% extends "account/base.html" %} 2 + 3 + {% load i18n %} 4 + {% load account %} 5 + 6 + {% block head_title %}{% trans "Password Reset" %}{% endblock %} 7 + 8 + {% block inner %} 9 + <h1>{% trans "Password Reset" %}</h1> 10 + 11 + {% if user.is_authenticated %} 12 + {% include "account/snippets/already_logged_in.html" %} 13 + {% endif %} 14 + 15 + <p>{% blocktrans %}We have sent you an e-mail. Please contact us if you do not receive it within a few minutes.{% endblocktrans %}</p> 16 + {% endblock %} 17 +
+25
care/templates/account/password_reset_from_key.html
··· 1 + {% extends "account/base.html" %} 2 + 3 + {% load i18n %} 4 + {% load crispy_forms_tags %} 5 + {% block head_title %}{% trans "Change Password" %}{% endblock %} 6 + 7 + {% block inner %} 8 + <h1>{% if token_fail %}{% trans "Bad Token" %}{% else %}{% trans "Change Password" %}{% endif %}</h1> 9 + 10 + {% if token_fail %} 11 + {% url 'account_reset_password' as passwd_reset_url %} 12 + <p>{% blocktrans %}The password reset link was invalid, possibly because it has already been used. Please request a <a href="{{ passwd_reset_url }}">new password reset</a>.{% endblocktrans %}</p> 13 + {% else %} 14 + {% if form %} 15 + <form method="POST" action="."> 16 + {% csrf_token %} 17 + {{ form|crispy }} 18 + <input class="btn btn-primary" type="submit" name="action" value="{% trans 'change password' %}"/> 19 + </form> 20 + {% else %} 21 + <p>{% trans 'Your password is now changed.' %}</p> 22 + {% endif %} 23 + {% endif %} 24 + {% endblock %} 25 +
+10
care/templates/account/password_reset_from_key_done.html
··· 1 + {% extends "account/base.html" %} 2 + 3 + {% load i18n %} 4 + {% block head_title %}{% trans "Change Password" %}{% endblock %} 5 + 6 + {% block inner %} 7 + <h1>{% trans "Change Password" %}</h1> 8 + <p>{% trans 'Your password is now changed.' %}</p> 9 + {% endblock %} 10 +
+17
care/templates/account/password_set.html
··· 1 + {% extends "account/base.html" %} 2 + 3 + {% load i18n %} 4 + {% load crispy_forms_tags %} 5 + 6 + {% block head_title %}{% trans "Set Password" %}{% endblock %} 7 + 8 + {% block inner %} 9 + <h1>{% trans "Set Password" %}</h1> 10 + 11 + <form method="POST" action="{% url 'account_set_password' %}" class="password_set"> 12 + {% csrf_token %} 13 + {{ form|crispy }} 14 + <input class="btn btn-primary" type="submit" name="action" value="{% trans 'Set Password' %}"/> 15 + </form> 16 + {% endblock %} 17 +
+23
care/templates/account/signup.html
··· 1 + {% extends "account/base.html" %} 2 + 3 + {% load i18n %} 4 + {% load crispy_forms_tags %} 5 + 6 + {% block head_title %}{% trans "Signup" %}{% endblock %} 7 + 8 + {% block inner %} 9 + <h1>{% trans "Sign Up" %}</h1> 10 + 11 + <p>{% blocktrans %}Already have an account? Then please <a href="{{ login_url }}">sign in</a>.{% endblocktrans %}</p> 12 + 13 + <form class="signup" id="signup_form" method="post" action="{% url 'account_signup' %}"> 14 + {% csrf_token %} 15 + {{ form|crispy }} 16 + {% if redirect_field_value %} 17 + <input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" /> 18 + {% endif %} 19 + <button class="btn btn-primary" type="submit">{% trans "Sign Up" %} &raquo;</button> 20 + </form> 21 + 22 + {% endblock %} 23 +
+12
care/templates/account/signup_closed.html
··· 1 + {% extends "account/base.html" %} 2 + 3 + {% load i18n %} 4 + 5 + {% block head_title %}{% trans "Sign Up Closed" %}{% endblock %} 6 + 7 + {% block inner %} 8 + <h1>{% trans "Sign Up Closed" %}</h1> 9 + 10 + <p>{% trans "We are sorry, but the sign up is currently closed." %}</p> 11 + {% endblock %} 12 +
+13
care/templates/account/verification_sent.html
··· 1 + {% extends "account/base.html" %} 2 + 3 + {% load i18n %} 4 + 5 + {% block head_title %}{% trans "Verify Your E-mail Address" %}{% endblock %} 6 + 7 + {% block inner %} 8 + <h1>{% trans "Verify Your E-mail Address" %}</h1> 9 + 10 + <p>{% blocktrans %}We have sent an e-mail to you for verification. Follow the link provided to finalize the signup process. Please contact us if you do not receive it within a few minutes.{% endblocktrans %}</p> 11 + 12 + {% endblock %} 13 +
+24
care/templates/account/verified_email_required.html
··· 1 + {% extends "account/base.html" %} 2 + 3 + {% load i18n %} 4 + 5 + {% block head_title %}{% trans "Verify Your E-mail Address" %}{% endblock %} 6 + 7 + {% block inner %} 8 + <h1>{% trans "Verify Your E-mail Address" %}</h1> 9 + 10 + {% url 'account_email' as email_url %} 11 + 12 + <p>{% blocktrans %}This part of the site requires us to verify that 13 + you are who you claim to be. For this purpose, we require that you 14 + verify ownership of your e-mail address. {% endblocktrans %}</p> 15 + 16 + <p>{% blocktrans %}We have sent an e-mail to you for 17 + verification. Please click on the link inside this e-mail. Please 18 + contact us if you do not receive it within a few minutes.{% endblocktrans %}</p> 19 + 20 + <p>{% blocktrans %}<strong>Note:</strong> you can still <a href="{{ email_url }}">change your e-mail address</a>.{% endblocktrans %}</p> 21 + 22 + 23 + {% endblock %} 24 +
+114
care/templates/base.html
··· 1 + {% load static i18n %}<!DOCTYPE html> 2 + <html lang="en"> 3 + <head> 4 + <meta charset="utf-8"> 5 + <meta http-equiv="x-ua-compatible" content="ie=edge"> 6 + <title>{% block title %}Care{% endblock title %}</title> 7 + <meta name="viewport" content="width=device-width, initial-scale=1.0"> 8 + <meta name="description" content=""> 9 + <meta name="author" content=""> 10 + 11 + <!-- HTML5 shim, for IE6-8 support of HTML5 elements --> 12 + <!--[if lt IE 9]> 13 + <script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script> 14 + <![endif]--> 15 + 16 + <link rel="icon" href="{% static 'images/favicons/favicon.ico' %}"> 17 + 18 + {% block css %} 19 + 20 + <!-- Latest compiled and minified Bootstrap CSS --> 21 + <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> 22 + 23 + 24 + <!-- Your stuff: Third-party CSS libraries go here --> 25 + 26 + <!-- This file stores project-specific CSS --> 27 + 28 + <link href="{% static 'css/project.css' %}" rel="stylesheet"> 29 + 30 + 31 + {% endblock %} 32 + 33 + </head> 34 + 35 + <body> 36 + 37 + <div class="mb-1"> 38 + <nav class="navbar navbar-expand-md navbar-light bg-light"> 39 + <button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> 40 + <span class="navbar-toggler-icon"></span> 41 + </button> 42 + <a class="navbar-brand" href="{% url 'home' %}">Care</a> 43 + 44 + <div class="collapse navbar-collapse" id="navbarSupportedContent"> 45 + <ul class="navbar-nav mr-auto"> 46 + <li class="nav-item active"> 47 + <a class="nav-link" href="{% url 'home' %}">Home <span class="sr-only">(current)</span></a> 48 + </li> 49 + <li class="nav-item"> 50 + <a class="nav-link" href="{% url 'about' %}">About</a> 51 + </li> 52 + {% if request.user.is_authenticated %} 53 + <li class="nav-item"> 54 + {# URL provided by django-allauth/account/urls.py #} 55 + <a class="nav-link" href="{% url 'users:detail' request.user.username %}">{% trans "My Profile" %}</a> 56 + </li> 57 + <li class="nav-item"> 58 + {# URL provided by django-allauth/account/urls.py #} 59 + <a class="nav-link" href="{% url 'account_logout' %}">{% trans "Sign Out" %}</a> 60 + </li> 61 + {% else %} 62 + <li class="nav-item"> 63 + {# URL provided by django-allauth/account/urls.py #} 64 + <a id="sign-up-link" class="nav-link" href="{% url 'account_signup' %}">{% trans "Sign Up" %}</a> 65 + </li> 66 + <li class="nav-item"> 67 + {# URL provided by django-allauth/account/urls.py #} 68 + <a id="log-in-link" class="nav-link" href="{% url 'account_login' %}">{% trans "Sign In" %}</a> 69 + </li> 70 + {% endif %} 71 + </ul> 72 + </div> 73 + </nav> 74 + 75 + </div> 76 + 77 + <div class="container"> 78 + 79 + {% if messages %} 80 + {% for message in messages %} 81 + <div class="alert {% if message.tags %}alert-{{ message.tags }}{% endif %}">{{ message }}<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button></div> 82 + {% endfor %} 83 + {% endif %} 84 + 85 + {% block content %} 86 + <p>Use this document as a way to quick start any new project.</p> 87 + {% endblock content %} 88 + 89 + </div> <!-- /container --> 90 + 91 + {% block modal %}{% endblock modal %} 92 + 93 + <!-- Le javascript 94 + ================================================== --> 95 + <!-- Placed at the end of the document so the pages load faster --> 96 + {% block javascript %} 97 + 98 + <!-- Bootstrap JS and its dependencies--> 99 + <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> 100 + <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script> 101 + <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script> 102 + 103 + <!-- Your stuff: Third-party javascript libraries go here --> 104 + 105 + 106 + <!-- place project specific Javascript in this file --> 107 + 108 + <script src="{% static 'js/project.js' %}"></script> 109 + 110 + 111 + {% endblock javascript %} 112 + </body> 113 + </html> 114 +
+1
care/templates/pages/about.html
··· 1 + {% extends "base.html" %}
+1
care/templates/pages/home.html
··· 1 + {% extends "base.html" %}
+36
care/templates/users/user_detail.html
··· 1 + {% extends "base.html" %} 2 + {% load static %} 3 + 4 + {% block title %}User: {{ object.username }}{% endblock %} 5 + 6 + {% block content %} 7 + <div class="container"> 8 + 9 + <div class="row"> 10 + <div class="col-sm-12"> 11 + 12 + <h2>{{ object.username }}</h2> 13 + {% if object.name %} 14 + <p>{{ object.name }}</p> 15 + {% endif %} 16 + </div> 17 + </div> 18 + 19 + {% if object == request.user %} 20 + <!-- Action buttons --> 21 + <div class="row"> 22 + 23 + <div class="col-sm-12"> 24 + <a class="btn btn-primary" href="{% url 'users:update' %}" role="button">My Info</a> 25 + <a class="btn btn-primary" href="{% url 'account_email' %}" role="button">E-Mail</a> 26 + <!-- Your Stuff: Custom user template urls --> 27 + </div> 28 + 29 + </div> 30 + <!-- End Action buttons --> 31 + {% endif %} 32 + 33 + 34 + </div> 35 + {% endblock content %} 36 +
+17
care/templates/users/user_form.html
··· 1 + {% extends "base.html" %} 2 + {% load crispy_forms_tags %} 3 + 4 + {% block title %}{{ user.username }}{% endblock %} 5 + 6 + {% block content %} 7 + <h1>{{ user.username }}</h1> 8 + <form class="form-horizontal" method="post" action="{% url 'users:update' %}"> 9 + {% csrf_token %} 10 + {{ form|crispy }} 11 + <div class="control-group"> 12 + <div class="controls"> 13 + <button type="submit" class="btn btn-primary">Update</button> 14 + </div> 15 + </div> 16 + </form> 17 + {% endblock %}
care/users/__init__.py

This is a binary file and will not be displayed.

+16
care/users/adapters.py
··· 1 + from typing import Any 2 + 3 + from allauth.account.adapter import DefaultAccountAdapter 4 + from allauth.socialaccount.adapter import DefaultSocialAccountAdapter 5 + from django.conf import settings 6 + from django.http import HttpRequest 7 + 8 + 9 + class AccountAdapter(DefaultAccountAdapter): 10 + def is_open_for_signup(self, request: HttpRequest): 11 + return getattr(settings, "ACCOUNT_ALLOW_REGISTRATION", True) 12 + 13 + 14 + class SocialAccountAdapter(DefaultSocialAccountAdapter): 15 + def is_open_for_signup(self, request: HttpRequest, sociallogin: Any): 16 + return getattr(settings, "ACCOUNT_ALLOW_REGISTRATION", True)
+17
care/users/admin.py
··· 1 + from django.contrib import admin 2 + from django.contrib.auth import admin as auth_admin 3 + from django.contrib.auth import get_user_model 4 + 5 + from care.users.forms import UserChangeForm, UserCreationForm 6 + 7 + User = get_user_model() 8 + 9 + 10 + @admin.register(User) 11 + class UserAdmin(auth_admin.UserAdmin): 12 + 13 + form = UserChangeForm 14 + add_form = UserCreationForm 15 + fieldsets = (("User", {"fields": ("name",)}),) + auth_admin.UserAdmin.fieldsets 16 + list_display = ["username", "name", "is_superuser"] 17 + search_fields = ["name"]
+13
care/users/api/serializers.py
··· 1 + from rest_framework import serializers 2 + 3 + from care.users.models import User 4 + 5 + 6 + class UserSerializer(serializers.ModelSerializer): 7 + class Meta: 8 + model = User 9 + fields = ["username", "email", "name", "url"] 10 + 11 + extra_kwargs = { 12 + "url": {"view_name": "api:user-detail", "lookup_field": "username"} 13 + }
+24
care/users/api/views.py
··· 1 + from django.contrib.auth import get_user_model 2 + from rest_framework import status 3 + from rest_framework.decorators import action 4 + from rest_framework.mixins import ListModelMixin, RetrieveModelMixin, UpdateModelMixin 5 + from rest_framework.response import Response 6 + from rest_framework.viewsets import GenericViewSet 7 + 8 + from .serializers import UserSerializer 9 + 10 + User = get_user_model() 11 + 12 + 13 + class UserViewSet(RetrieveModelMixin, ListModelMixin, UpdateModelMixin, GenericViewSet): 14 + serializer_class = UserSerializer 15 + queryset = User.objects.all() 16 + lookup_field = "username" 17 + 18 + def get_queryset(self, *args, **kwargs): 19 + return self.queryset.filter(id=self.request.user.id) 20 + 21 + @action(detail=False, methods=["GET"]) 22 + def me(self, request): 23 + serializer = UserSerializer(request.user, context={"request": request}) 24 + return Response(status=status.HTTP_200_OK, data=serializer.data)
+13
care/users/apps.py
··· 1 + from django.apps import AppConfig 2 + from django.utils.translation import gettext_lazy as _ 3 + 4 + 5 + class UsersConfig(AppConfig): 6 + name = "care.users" 7 + verbose_name = _("Users") 8 + 9 + def ready(self): 10 + try: 11 + import care.users.signals # noqa F401 12 + except ImportError: 13 + pass
+30
care/users/forms.py
··· 1 + from django.contrib.auth import forms, get_user_model 2 + from django.core.exceptions import ValidationError 3 + from django.utils.translation import ugettext_lazy as _ 4 + 5 + User = get_user_model() 6 + 7 + 8 + class UserChangeForm(forms.UserChangeForm): 9 + class Meta(forms.UserChangeForm.Meta): 10 + model = User 11 + 12 + 13 + class UserCreationForm(forms.UserCreationForm): 14 + 15 + error_message = forms.UserCreationForm.error_messages.update( 16 + {"duplicate_username": _("This username has already been taken.")} 17 + ) 18 + 19 + class Meta(forms.UserCreationForm.Meta): 20 + model = User 21 + 22 + def clean_username(self): 23 + username = self.cleaned_data["username"] 24 + 25 + try: 26 + User.objects.get(username=username) 27 + except User.DoesNotExist: 28 + return username 29 + 30 + raise ValidationError(self.error_messages["duplicate_username"])
+132
care/users/migrations/0001_initial.py
··· 1 + import django.contrib.auth.models 2 + import django.contrib.auth.validators 3 + from django.db import migrations, models 4 + import django.utils.timezone 5 + 6 + 7 + class Migration(migrations.Migration): 8 + 9 + initial = True 10 + 11 + dependencies = [("auth", "0008_alter_user_username_max_length")] 12 + 13 + operations = [ 14 + migrations.CreateModel( 15 + name="User", 16 + fields=[ 17 + ( 18 + "id", 19 + models.AutoField( 20 + auto_created=True, 21 + primary_key=True, 22 + serialize=False, 23 + verbose_name="ID", 24 + ), 25 + ), 26 + ("password", models.CharField(max_length=128, verbose_name="password")), 27 + ( 28 + "last_login", 29 + models.DateTimeField( 30 + blank=True, null=True, verbose_name="last login" 31 + ), 32 + ), 33 + ( 34 + "is_superuser", 35 + models.BooleanField( 36 + default=False, 37 + help_text="Designates that this user has all permissions without explicitly assigning them.", 38 + verbose_name="superuser status", 39 + ), 40 + ), 41 + ( 42 + "username", 43 + models.CharField( 44 + error_messages={ 45 + "unique": "A user with that username already exists." 46 + }, 47 + help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.", 48 + max_length=150, 49 + unique=True, 50 + validators=[ 51 + django.contrib.auth.validators.UnicodeUsernameValidator() 52 + ], 53 + verbose_name="username", 54 + ), 55 + ), 56 + ( 57 + "first_name", 58 + models.CharField( 59 + blank=True, max_length=30, verbose_name="first name" 60 + ), 61 + ), 62 + ( 63 + "last_name", 64 + models.CharField( 65 + blank=True, max_length=150, verbose_name="last name" 66 + ), 67 + ), 68 + ( 69 + "email", 70 + models.EmailField( 71 + blank=True, max_length=254, verbose_name="email address" 72 + ), 73 + ), 74 + ( 75 + "is_staff", 76 + models.BooleanField( 77 + default=False, 78 + help_text="Designates whether the user can log into this admin site.", 79 + verbose_name="staff status", 80 + ), 81 + ), 82 + ( 83 + "is_active", 84 + models.BooleanField( 85 + default=True, 86 + help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.", 87 + verbose_name="active", 88 + ), 89 + ), 90 + ( 91 + "date_joined", 92 + models.DateTimeField( 93 + default=django.utils.timezone.now, verbose_name="date joined" 94 + ), 95 + ), 96 + ( 97 + "name", 98 + models.CharField( 99 + blank=True, max_length=255, verbose_name="Name of User" 100 + ), 101 + ), 102 + ( 103 + "groups", 104 + models.ManyToManyField( 105 + blank=True, 106 + help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.", 107 + related_name="user_set", 108 + related_query_name="user", 109 + to="auth.Group", 110 + verbose_name="groups", 111 + ), 112 + ), 113 + ( 114 + "user_permissions", 115 + models.ManyToManyField( 116 + blank=True, 117 + help_text="Specific permissions for this user.", 118 + related_name="user_set", 119 + related_query_name="user", 120 + to="auth.Permission", 121 + verbose_name="user permissions", 122 + ), 123 + ), 124 + ], 125 + options={ 126 + "verbose_name_plural": "users", 127 + "verbose_name": "user", 128 + "abstract": False, 129 + }, 130 + managers=[("objects", django.contrib.auth.models.UserManager())], 131 + ) 132 + ]
care/users/migrations/__init__.py

This is a binary file and will not be displayed.

+14
care/users/models.py
··· 1 + from django.contrib.auth.models import AbstractUser 2 + from django.db.models import CharField 3 + from django.urls import reverse 4 + from django.utils.translation import ugettext_lazy as _ 5 + 6 + 7 + class User(AbstractUser): 8 + 9 + # First Name and Last Name do not cover name patterns 10 + # around the globe. 11 + name = CharField(_("Name of User"), blank=True, max_length=255) 12 + 13 + def get_absolute_url(self): 14 + return reverse("users:detail", kwargs={"username": self.username})
care/users/tests/__init__.py

This is a binary file and will not be displayed.

+31
care/users/tests/factories.py
··· 1 + from typing import Any, Sequence 2 + 3 + from django.contrib.auth import get_user_model 4 + from factory import DjangoModelFactory, Faker, post_generation 5 + 6 + 7 + class UserFactory(DjangoModelFactory): 8 + 9 + username = Faker("user_name") 10 + email = Faker("email") 11 + name = Faker("name") 12 + 13 + @post_generation 14 + def password(self, create: bool, extracted: Sequence[Any], **kwargs): 15 + password = ( 16 + extracted 17 + if extracted 18 + else Faker( 19 + "password", 20 + length=42, 21 + special_chars=True, 22 + digits=True, 23 + upper_case=True, 24 + lower_case=True, 25 + ).generate(extra_kwargs={}) 26 + ) 27 + self.set_password(password) 28 + 29 + class Meta: 30 + model = get_user_model() 31 + django_get_or_create = ["username"]
+40
care/users/tests/test_forms.py
··· 1 + import pytest 2 + 3 + from care.users.forms import UserCreationForm 4 + from care.users.tests.factories import UserFactory 5 + 6 + pytestmark = pytest.mark.django_db 7 + 8 + 9 + class TestUserCreationForm: 10 + def test_clean_username(self): 11 + # A user with proto_user params does not exist yet. 12 + proto_user = UserFactory.build() 13 + 14 + form = UserCreationForm( 15 + { 16 + "username": proto_user.username, 17 + "password1": proto_user._password, 18 + "password2": proto_user._password, 19 + } 20 + ) 21 + 22 + assert form.is_valid() 23 + assert form.clean_username() == proto_user.username 24 + 25 + # Creating a user. 26 + form.save() 27 + 28 + # The user with proto_user params already exists, 29 + # hence cannot be created. 30 + form = UserCreationForm( 31 + { 32 + "username": proto_user.username, 33 + "password1": proto_user._password, 34 + "password2": proto_user._password, 35 + } 36 + ) 37 + 38 + assert not form.is_valid() 39 + assert len(form.errors) == 1 40 + assert "username" in form.errors
+9
care/users/tests/test_models.py
··· 1 + import pytest 2 + 3 + from care.users.models import User 4 + 5 + pytestmark = pytest.mark.django_db 6 + 7 + 8 + def test_user_get_absolute_url(user: User): 9 + assert user.get_absolute_url() == f"/users/{user.username}/"
+24
care/users/tests/test_urls.py
··· 1 + import pytest 2 + from django.urls import resolve, reverse 3 + 4 + from care.users.models import User 5 + 6 + pytestmark = pytest.mark.django_db 7 + 8 + 9 + def test_detail(user: User): 10 + assert ( 11 + reverse("users:detail", kwargs={"username": user.username}) 12 + == f"/users/{user.username}/" 13 + ) 14 + assert resolve(f"/users/{user.username}/").view_name == "users:detail" 15 + 16 + 17 + def test_update(): 18 + assert reverse("users:update") == "/users/~update/" 19 + assert resolve("/users/~update/").view_name == "users:update" 20 + 21 + 22 + def test_redirect(): 23 + assert reverse("users:redirect") == "/users/~redirect/" 24 + assert resolve("/users/~redirect/").view_name == "users:redirect"
+46
care/users/tests/test_views.py
··· 1 + import pytest 2 + from django.test import RequestFactory 3 + 4 + from care.users.models import User 5 + from care.users.views import UserRedirectView, UserUpdateView 6 + 7 + pytestmark = pytest.mark.django_db 8 + 9 + 10 + class TestUserUpdateView: 11 + """ 12 + TODO: 13 + extracting view initialization code as class-scoped fixture 14 + would be great if only pytest-django supported non-function-scoped 15 + fixture db access -- this is a work-in-progress for now: 16 + https://github.com/pytest-dev/pytest-django/pull/258 17 + """ 18 + 19 + def test_get_success_url(self, user: User, request_factory: RequestFactory): 20 + view = UserUpdateView() 21 + request = request_factory.get("/fake-url/") 22 + request.user = user 23 + 24 + view.request = request 25 + 26 + assert view.get_success_url() == f"/users/{user.username}/" 27 + 28 + def test_get_object(self, user: User, request_factory: RequestFactory): 29 + view = UserUpdateView() 30 + request = request_factory.get("/fake-url/") 31 + request.user = user 32 + 33 + view.request = request 34 + 35 + assert view.get_object() == user 36 + 37 + 38 + class TestUserRedirectView: 39 + def test_get_redirect_url(self, user: User, request_factory: RequestFactory): 40 + view = UserRedirectView() 41 + request = request_factory.get("/fake-url") 42 + request.user = user 43 + 44 + view.request = request 45 + 46 + assert view.get_redirect_url() == f"/users/{user.username}/"
+14
care/users/urls.py
··· 1 + from django.urls import path 2 + 3 + from care.users.views import ( 4 + user_detail_view, 5 + user_redirect_view, 6 + user_update_view, 7 + ) 8 + 9 + app_name = "users" 10 + urlpatterns = [ 11 + path("~redirect/", view=user_redirect_view, name="redirect"), 12 + path("~update/", view=user_update_view, name="update"), 13 + path("<str:username>/", view=user_detail_view, name="detail"), 14 + ]
+50
care/users/views.py
··· 1 + from django.contrib import messages 2 + from django.contrib.auth import get_user_model 3 + from django.contrib.auth.mixins import LoginRequiredMixin 4 + from django.urls import reverse 5 + from django.utils.translation import ugettext_lazy as _ 6 + from django.views.generic import DetailView, RedirectView, UpdateView 7 + 8 + User = get_user_model() 9 + 10 + 11 + class UserDetailView(LoginRequiredMixin, DetailView): 12 + 13 + model = User 14 + slug_field = "username" 15 + slug_url_kwarg = "username" 16 + 17 + 18 + user_detail_view = UserDetailView.as_view() 19 + 20 + 21 + class UserUpdateView(LoginRequiredMixin, UpdateView): 22 + 23 + model = User 24 + fields = ["name"] 25 + 26 + def get_success_url(self): 27 + return reverse("users:detail", kwargs={"username": self.request.user.username}) 28 + 29 + def get_object(self): 30 + return User.objects.get(username=self.request.user.username) 31 + 32 + def form_valid(self, form): 33 + messages.add_message( 34 + self.request, messages.INFO, _("Infos successfully updated") 35 + ) 36 + return super().form_valid(form) 37 + 38 + 39 + user_update_view = UserUpdateView.as_view() 40 + 41 + 42 + class UserRedirectView(LoginRequiredMixin, RedirectView): 43 + 44 + permanent = False 45 + 46 + def get_redirect_url(self): 47 + return reverse("users:detail", kwargs={"username": self.request.user.username}) 48 + 49 + 50 + user_redirect_view = UserRedirectView.as_view()
care/utils/__init__.py

This is a binary file and will not be displayed.

+5
care/utils/context_processors.py
··· 1 + from django.conf import settings 2 + 3 + 4 + def settings_context(_request): 5 + return {"settings": settings}
config/__init__.py

This is a binary file and will not be displayed.

+15
config/api_router.py
··· 1 + from django.conf import settings 2 + from rest_framework.routers import DefaultRouter, SimpleRouter 3 + 4 + from care.users.api.views import UserViewSet 5 + 6 + if settings.DEBUG: 7 + router = DefaultRouter() 8 + else: 9 + router = SimpleRouter() 10 + 11 + router.register("users", UserViewSet) 12 + 13 + 14 + app_name = "api" 15 + urlpatterns = router.urls
config/settings/__init__.py

This is a binary file and will not be displayed.

+273
config/settings/base.py
··· 1 + """ 2 + Base settings to build other settings files upon. 3 + """ 4 + 5 + import environ 6 + 7 + ROOT_DIR = ( 8 + environ.Path(__file__) - 3 9 + ) # (care/config/settings/base.py - 3 = care/) 10 + APPS_DIR = ROOT_DIR.path("care") 11 + 12 + env = environ.Env() 13 + 14 + READ_DOT_ENV_FILE = env.bool("DJANGO_READ_DOT_ENV_FILE", default=False) 15 + if READ_DOT_ENV_FILE: 16 + # OS environment variables take precedence over variables from .env 17 + env.read_env(str(ROOT_DIR.path(".env"))) 18 + 19 + # GENERAL 20 + # ------------------------------------------------------------------------------ 21 + # https://docs.djangoproject.com/en/dev/ref/settings/#debug 22 + DEBUG = env.bool("DJANGO_DEBUG", False) 23 + # Local time zone. Choices are 24 + # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name 25 + # though not all of them may be available with every OS. 26 + # In Windows, this must be set to your system time zone. 27 + TIME_ZONE = "UTC" 28 + # https://docs.djangoproject.com/en/dev/ref/settings/#language-code 29 + LANGUAGE_CODE = "en-us" 30 + # https://docs.djangoproject.com/en/dev/ref/settings/#site-id 31 + SITE_ID = 1 32 + # https://docs.djangoproject.com/en/dev/ref/settings/#use-i18n 33 + USE_I18N = True 34 + # https://docs.djangoproject.com/en/dev/ref/settings/#use-l10n 35 + USE_L10N = True 36 + # https://docs.djangoproject.com/en/dev/ref/settings/#use-tz 37 + USE_TZ = True 38 + # https://docs.djangoproject.com/en/dev/ref/settings/#locale-paths 39 + LOCALE_PATHS = [ROOT_DIR.path("locale")] 40 + 41 + # DATABASES 42 + # ------------------------------------------------------------------------------ 43 + # https://docs.djangoproject.com/en/dev/ref/settings/#databases 44 + 45 + DATABASES = { 46 + "default": env.db("DATABASE_URL", default="postgres:///care") 47 + } 48 + DATABASES["default"]["ATOMIC_REQUESTS"] = True 49 + 50 + # URLS 51 + # ------------------------------------------------------------------------------ 52 + # https://docs.djangoproject.com/en/dev/ref/settings/#root-urlconf 53 + ROOT_URLCONF = "config.urls" 54 + # https://docs.djangoproject.com/en/dev/ref/settings/#wsgi-application 55 + WSGI_APPLICATION = "config.wsgi.application" 56 + 57 + # APPS 58 + # ------------------------------------------------------------------------------ 59 + DJANGO_APPS = [ 60 + "django.contrib.auth", 61 + "django.contrib.contenttypes", 62 + "django.contrib.sessions", 63 + "django.contrib.sites", 64 + "django.contrib.messages", 65 + "django.contrib.staticfiles", 66 + # "django.contrib.humanize", # Handy template tags 67 + "django.contrib.admin", 68 + "django.forms", 69 + ] 70 + THIRD_PARTY_APPS = [ 71 + "crispy_forms", 72 + "allauth", 73 + "allauth.account", 74 + "allauth.socialaccount", 75 + ] 76 + 77 + LOCAL_APPS = [ 78 + "care.users.apps.UsersConfig", 79 + # Your stuff: custom apps go here 80 + ] 81 + # https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps 82 + INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS 83 + 84 + # MIGRATIONS 85 + # ------------------------------------------------------------------------------ 86 + # https://docs.djangoproject.com/en/dev/ref/settings/#migration-modules 87 + MIGRATION_MODULES = {"sites": "care.contrib.sites.migrations"} 88 + 89 + # AUTHENTICATION 90 + # ------------------------------------------------------------------------------ 91 + # https://docs.djangoproject.com/en/dev/ref/settings/#authentication-backends 92 + AUTHENTICATION_BACKENDS = [ 93 + "django.contrib.auth.backends.ModelBackend", 94 + "allauth.account.auth_backends.AuthenticationBackend", 95 + ] 96 + # https://docs.djangoproject.com/en/dev/ref/settings/#auth-user-model 97 + AUTH_USER_MODEL = "users.User" 98 + # https://docs.djangoproject.com/en/dev/ref/settings/#login-redirect-url 99 + LOGIN_REDIRECT_URL = "users:redirect" 100 + # https://docs.djangoproject.com/en/dev/ref/settings/#login-url 101 + LOGIN_URL = "account_login" 102 + 103 + # PASSWORDS 104 + # ------------------------------------------------------------------------------ 105 + # https://docs.djangoproject.com/en/dev/ref/settings/#password-hashers 106 + PASSWORD_HASHERS = [ 107 + # https://docs.djangoproject.com/en/dev/topics/auth/passwords/#using-argon2-with-django 108 + "django.contrib.auth.hashers.Argon2PasswordHasher", 109 + "django.contrib.auth.hashers.PBKDF2PasswordHasher", 110 + "django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher", 111 + "django.contrib.auth.hashers.BCryptSHA256PasswordHasher", 112 + ] 113 + # https://docs.djangoproject.com/en/dev/ref/settings/#auth-password-validators 114 + AUTH_PASSWORD_VALIDATORS = [ 115 + { 116 + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator" 117 + }, 118 + {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"}, 119 + {"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"}, 120 + {"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"}, 121 + ] 122 + 123 + # MIDDLEWARE 124 + # ------------------------------------------------------------------------------ 125 + # https://docs.djangoproject.com/en/dev/ref/settings/#middleware 126 + MIDDLEWARE = [ 127 + "django.middleware.security.SecurityMiddleware", 128 + "whitenoise.middleware.WhiteNoiseMiddleware", 129 + "django.contrib.sessions.middleware.SessionMiddleware", 130 + "django.middleware.locale.LocaleMiddleware", 131 + "django.middleware.common.CommonMiddleware", 132 + "django.middleware.csrf.CsrfViewMiddleware", 133 + "django.contrib.auth.middleware.AuthenticationMiddleware", 134 + "django.contrib.messages.middleware.MessageMiddleware", 135 + "django.middleware.common.BrokenLinkEmailsMiddleware", 136 + "django.middleware.clickjacking.XFrameOptionsMiddleware", 137 + ] 138 + 139 + # STATIC 140 + # ------------------------------------------------------------------------------ 141 + # https://docs.djangoproject.com/en/dev/ref/settings/#static-root 142 + STATIC_ROOT = str(ROOT_DIR("staticfiles")) 143 + # https://docs.djangoproject.com/en/dev/ref/settings/#static-url 144 + STATIC_URL = "/static/" 145 + # https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS 146 + STATICFILES_DIRS = [str(APPS_DIR.path("static"))] 147 + # https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#staticfiles-finders 148 + STATICFILES_FINDERS = [ 149 + "django.contrib.staticfiles.finders.FileSystemFinder", 150 + "django.contrib.staticfiles.finders.AppDirectoriesFinder", 151 + ] 152 + 153 + # MEDIA 154 + # ------------------------------------------------------------------------------ 155 + # https://docs.djangoproject.com/en/dev/ref/settings/#media-root 156 + MEDIA_ROOT = str(APPS_DIR("media")) 157 + # https://docs.djangoproject.com/en/dev/ref/settings/#media-url 158 + MEDIA_URL = "/media/" 159 + 160 + # TEMPLATES 161 + # ------------------------------------------------------------------------------ 162 + # https://docs.djangoproject.com/en/dev/ref/settings/#templates 163 + TEMPLATES = [ 164 + { 165 + # https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-TEMPLATES-BACKEND 166 + "BACKEND": "django.template.backends.django.DjangoTemplates", 167 + # https://docs.djangoproject.com/en/dev/ref/settings/#template-dirs 168 + "DIRS": [str(APPS_DIR.path("templates"))], 169 + "OPTIONS": { 170 + # https://docs.djangoproject.com/en/dev/ref/settings/#template-loaders 171 + # https://docs.djangoproject.com/en/dev/ref/templates/api/#loader-types 172 + "loaders": [ 173 + "django.template.loaders.filesystem.Loader", 174 + "django.template.loaders.app_directories.Loader", 175 + ], 176 + # https://docs.djangoproject.com/en/dev/ref/settings/#template-context-processors 177 + "context_processors": [ 178 + "django.template.context_processors.debug", 179 + "django.template.context_processors.request", 180 + "django.contrib.auth.context_processors.auth", 181 + "django.template.context_processors.i18n", 182 + "django.template.context_processors.media", 183 + "django.template.context_processors.static", 184 + "django.template.context_processors.tz", 185 + "django.contrib.messages.context_processors.messages", 186 + "care.utils.context_processors.settings_context", 187 + ], 188 + }, 189 + } 190 + ] 191 + 192 + # https://docs.djangoproject.com/en/dev/ref/settings/#form-renderer 193 + FORM_RENDERER = "django.forms.renderers.TemplatesSetting" 194 + 195 + # http://django-crispy-forms.readthedocs.io/en/latest/install.html#template-packs 196 + CRISPY_TEMPLATE_PACK = "bootstrap4" 197 + 198 + # FIXTURES 199 + # ------------------------------------------------------------------------------ 200 + # https://docs.djangoproject.com/en/dev/ref/settings/#fixture-dirs 201 + FIXTURE_DIRS = (str(APPS_DIR.path("fixtures")),) 202 + 203 + # SECURITY 204 + # ------------------------------------------------------------------------------ 205 + # https://docs.djangoproject.com/en/dev/ref/settings/#session-cookie-httponly 206 + SESSION_COOKIE_HTTPONLY = True 207 + # https://docs.djangoproject.com/en/dev/ref/settings/#csrf-cookie-httponly 208 + CSRF_COOKIE_HTTPONLY = True 209 + # https://docs.djangoproject.com/en/dev/ref/settings/#secure-browser-xss-filter 210 + SECURE_BROWSER_XSS_FILTER = True 211 + # https://docs.djangoproject.com/en/dev/ref/settings/#x-frame-options 212 + X_FRAME_OPTIONS = "DENY" 213 + 214 + # EMAIL 215 + # ------------------------------------------------------------------------------ 216 + # https://docs.djangoproject.com/en/dev/ref/settings/#email-backend 217 + EMAIL_BACKEND = env( 218 + "DJANGO_EMAIL_BACKEND", default="django.core.mail.backends.smtp.EmailBackend" 219 + ) 220 + # https://docs.djangoproject.com/en/2.2/ref/settings/#email-timeout 221 + EMAIL_TIMEOUT = 5 222 + 223 + # ADMIN 224 + # ------------------------------------------------------------------------------ 225 + # Django Admin URL. 226 + ADMIN_URL = "admin/" 227 + # https://docs.djangoproject.com/en/dev/ref/settings/#admins 228 + ADMINS = [("""👪""", "admin@coronasafe.in")] 229 + # https://docs.djangoproject.com/en/dev/ref/settings/#managers 230 + MANAGERS = ADMINS 231 + 232 + # LOGGING 233 + # ------------------------------------------------------------------------------ 234 + # https://docs.djangoproject.com/en/dev/ref/settings/#logging 235 + # See https://docs.djangoproject.com/en/dev/topics/logging for 236 + # more details on how to customize your logging configuration. 237 + LOGGING = { 238 + "version": 1, 239 + "disable_existing_loggers": False, 240 + "formatters": { 241 + "verbose": { 242 + "format": "%(levelname)s %(asctime)s %(module)s " 243 + "%(process)d %(thread)d %(message)s" 244 + } 245 + }, 246 + "handlers": { 247 + "console": { 248 + "level": "DEBUG", 249 + "class": "logging.StreamHandler", 250 + "formatter": "verbose", 251 + } 252 + }, 253 + "root": {"level": "INFO", "handlers": ["console"]}, 254 + } 255 + 256 + 257 + # django-allauth 258 + # ------------------------------------------------------------------------------ 259 + ACCOUNT_ALLOW_REGISTRATION = env.bool("DJANGO_ACCOUNT_ALLOW_REGISTRATION", True) 260 + # https://django-allauth.readthedocs.io/en/latest/configuration.html 261 + ACCOUNT_AUTHENTICATION_METHOD = "username" 262 + # https://django-allauth.readthedocs.io/en/latest/configuration.html 263 + ACCOUNT_EMAIL_REQUIRED = True 264 + # https://django-allauth.readthedocs.io/en/latest/configuration.html 265 + ACCOUNT_EMAIL_VERIFICATION = "mandatory" 266 + # https://django-allauth.readthedocs.io/en/latest/configuration.html 267 + ACCOUNT_ADAPTER = "care.users.adapters.AccountAdapter" 268 + # https://django-allauth.readthedocs.io/en/latest/configuration.html 269 + SOCIALACCOUNT_ADAPTER = "care.users.adapters.SocialAccountAdapter" 270 + 271 + 272 + # Your stuff... 273 + # ------------------------------------------------------------------------------
+60
config/settings/local.py
··· 1 + from .base import * # noqa 2 + from .base import env 3 + 4 + # GENERAL 5 + # ------------------------------------------------------------------------------ 6 + # https://docs.djangoproject.com/en/dev/ref/settings/#debug 7 + DEBUG = True 8 + # https://docs.djangoproject.com/en/dev/ref/settings/#secret-key 9 + SECRET_KEY = env( 10 + "DJANGO_SECRET_KEY", 11 + default="eXZQzOzx8gV38rDG0Z0fFZWweUGl3LwMZ9aTKqJiXQTI0nKMh0Z7sbHfqT8KFEnd", 12 + ) 13 + # https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts 14 + ALLOWED_HOSTS = ["localhost", "0.0.0.0", "127.0.0.1"] 15 + 16 + # CACHES 17 + # ------------------------------------------------------------------------------ 18 + # https://docs.djangoproject.com/en/dev/ref/settings/#caches 19 + CACHES = { 20 + "default": { 21 + "BACKEND": "django.core.cache.backends.locmem.LocMemCache", 22 + "LOCATION": "", 23 + } 24 + } 25 + 26 + # EMAIL 27 + # ------------------------------------------------------------------------------ 28 + # https://docs.djangoproject.com/en/dev/ref/settings/#email-host 29 + EMAIL_HOST = "localhost" 30 + # https://docs.djangoproject.com/en/dev/ref/settings/#email-port 31 + EMAIL_PORT = 1025 32 + 33 + # WhiteNoise 34 + # ------------------------------------------------------------------------------ 35 + # http://whitenoise.evans.io/en/latest/django.html#using-whitenoise-in-development 36 + INSTALLED_APPS = ["whitenoise.runserver_nostatic"] + INSTALLED_APPS # noqa F405 37 + 38 + 39 + # django-debug-toolbar 40 + # ------------------------------------------------------------------------------ 41 + # https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#prerequisites 42 + INSTALLED_APPS += ["debug_toolbar"] # noqa F405 43 + # https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#middleware 44 + MIDDLEWARE += ["debug_toolbar.middleware.DebugToolbarMiddleware"] # noqa F405 45 + # https://django-debug-toolbar.readthedocs.io/en/latest/configuration.html#debug-toolbar-config 46 + DEBUG_TOOLBAR_CONFIG = { 47 + "DISABLE_PANELS": ["debug_toolbar.panels.redirects.RedirectsPanel"], 48 + "SHOW_TEMPLATE_CONTEXT": True, 49 + } 50 + # https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#internal-ips 51 + INTERNAL_IPS = ["127.0.0.1", "10.0.2.2"] 52 + 53 + 54 + # django-extensions 55 + # ------------------------------------------------------------------------------ 56 + # https://django-extensions.readthedocs.io/en/latest/installation_instructions.html#configuration 57 + INSTALLED_APPS += ["django_extensions"] # noqa F405 58 + 59 + # Your stuff... 60 + # ------------------------------------------------------------------------------
+168
config/settings/production.py
··· 1 + """isort:skip_file""" 2 + import logging 3 + 4 + import sentry_sdk 5 + 6 + from sentry_sdk.integrations.django import DjangoIntegration 7 + from sentry_sdk.integrations.logging import LoggingIntegration 8 + 9 + from .base import * # noqa 10 + from .base import env 11 + 12 + # GENERAL 13 + # ------------------------------------------------------------------------------ 14 + # https://docs.djangoproject.com/en/dev/ref/settings/#secret-key 15 + SECRET_KEY = env("DJANGO_SECRET_KEY") 16 + # https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts 17 + ALLOWED_HOSTS = env.list("DJANGO_ALLOWED_HOSTS", default=["coronasafe.in"]) 18 + 19 + # DATABASES 20 + # ------------------------------------------------------------------------------ 21 + DATABASES["default"] = env.db("DATABASE_URL") # noqa F405 22 + DATABASES["default"]["ATOMIC_REQUESTS"] = True # noqa F405 23 + DATABASES["default"]["CONN_MAX_AGE"] = env.int("CONN_MAX_AGE", default=60) # noqa F405 24 + 25 + # CACHES 26 + # ------------------------------------------------------------------------------ 27 + CACHES = { 28 + "default": { 29 + "BACKEND": "django_redis.cache.RedisCache", 30 + "LOCATION": env("REDIS_URL"), 31 + "OPTIONS": { 32 + "CLIENT_CLASS": "django_redis.client.DefaultClient", 33 + # Mimicing memcache behavior. 34 + # http://niwinz.github.io/django-redis/latest/#_memcached_exceptions_behavior 35 + "IGNORE_EXCEPTIONS": True, 36 + }, 37 + } 38 + } 39 + 40 + # SECURITY 41 + # ------------------------------------------------------------------------------ 42 + # https://docs.djangoproject.com/en/dev/ref/settings/#secure-proxy-ssl-header 43 + SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") 44 + # https://docs.djangoproject.com/en/dev/ref/settings/#secure-ssl-redirect 45 + SECURE_SSL_REDIRECT = env.bool("DJANGO_SECURE_SSL_REDIRECT", default=True) 46 + # https://docs.djangoproject.com/en/dev/ref/settings/#session-cookie-secure 47 + SESSION_COOKIE_SECURE = True 48 + # https://docs.djangoproject.com/en/dev/ref/settings/#csrf-cookie-secure 49 + CSRF_COOKIE_SECURE = True 50 + # https://docs.djangoproject.com/en/dev/topics/security/#ssl-https 51 + # https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-seconds 52 + # TODO: set this to 60 seconds first and then to 518400 once you prove the former works 53 + SECURE_HSTS_SECONDS = 60 54 + # https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-include-subdomains 55 + SECURE_HSTS_INCLUDE_SUBDOMAINS = env.bool( 56 + "DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS", default=True 57 + ) 58 + # https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-preload 59 + SECURE_HSTS_PRELOAD = env.bool("DJANGO_SECURE_HSTS_PRELOAD", default=True) 60 + # https://docs.djangoproject.com/en/dev/ref/middleware/#x-content-type-options-nosniff 61 + SECURE_CONTENT_TYPE_NOSNIFF = env.bool( 62 + "DJANGO_SECURE_CONTENT_TYPE_NOSNIFF", default=True 63 + ) 64 + 65 + # STATIC 66 + # ------------------------ 67 + STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage" 68 + # MEDIA 69 + # ------------------------------------------------------------------------------ 70 + 71 + # TEMPLATES 72 + # ------------------------------------------------------------------------------ 73 + # https://docs.djangoproject.com/en/dev/ref/settings/#templates 74 + TEMPLATES[-1]["OPTIONS"]["loaders"] = [ # type: ignore[index] # noqa F405 75 + ( 76 + "django.template.loaders.cached.Loader", 77 + [ 78 + "django.template.loaders.filesystem.Loader", 79 + "django.template.loaders.app_directories.Loader", 80 + ], 81 + ) 82 + ] 83 + 84 + # EMAIL 85 + # ------------------------------------------------------------------------------ 86 + # https://docs.djangoproject.com/en/dev/ref/settings/#default-from-email 87 + DEFAULT_FROM_EMAIL = env( 88 + "DJANGO_DEFAULT_FROM_EMAIL", default="Care <noreply@coronasafe.in>" 89 + ) 90 + # https://docs.djangoproject.com/en/dev/ref/settings/#server-email 91 + SERVER_EMAIL = env("DJANGO_SERVER_EMAIL", default=DEFAULT_FROM_EMAIL) 92 + # https://docs.djangoproject.com/en/dev/ref/settings/#email-subject-prefix 93 + EMAIL_SUBJECT_PREFIX = env( 94 + "DJANGO_EMAIL_SUBJECT_PREFIX", default="[Care]" 95 + ) 96 + 97 + # ADMIN 98 + # ------------------------------------------------------------------------------ 99 + # Django Admin URL regex. 100 + ADMIN_URL = env("DJANGO_ADMIN_URL") 101 + 102 + # Anymail 103 + # ------------------------------------------------------------------------------ 104 + # https://anymail.readthedocs.io/en/stable/installation/#installing-anymail 105 + INSTALLED_APPS += ["anymail"] # noqa F405 106 + # https://docs.djangoproject.com/en/dev/ref/settings/#email-backend 107 + # https://anymail.readthedocs.io/en/stable/installation/#anymail-settings-reference 108 + # https://anymail.readthedocs.io/en/stable/esps/mailgun/ 109 + EMAIL_BACKEND = "anymail.backends.mailgun.EmailBackend" 110 + ANYMAIL = { 111 + "MAILGUN_API_KEY": env("MAILGUN_API_KEY"), 112 + "MAILGUN_SENDER_DOMAIN": env("MAILGUN_DOMAIN"), 113 + "MAILGUN_API_URL": env("MAILGUN_API_URL", default="https://api.mailgun.net/v3"), 114 + } 115 + 116 + 117 + # LOGGING 118 + # ------------------------------------------------------------------------------ 119 + # https://docs.djangoproject.com/en/dev/ref/settings/#logging 120 + # See https://docs.djangoproject.com/en/dev/topics/logging for 121 + # more details on how to customize your logging configuration. 122 + 123 + LOGGING = { 124 + "version": 1, 125 + "disable_existing_loggers": True, 126 + "formatters": { 127 + "verbose": { 128 + "format": "%(levelname)s %(asctime)s %(module)s " 129 + "%(process)d %(thread)d %(message)s" 130 + } 131 + }, 132 + "handlers": { 133 + "console": { 134 + "level": "DEBUG", 135 + "class": "logging.StreamHandler", 136 + "formatter": "verbose", 137 + } 138 + }, 139 + "root": {"level": "INFO", "handlers": ["console"]}, 140 + "loggers": { 141 + "django.db.backends": { 142 + "level": "ERROR", 143 + "handlers": ["console"], 144 + "propagate": False, 145 + }, 146 + # Errors logged by the SDK itself 147 + "sentry_sdk": {"level": "ERROR", "handlers": ["console"], "propagate": False}, 148 + "django.security.DisallowedHost": { 149 + "level": "ERROR", 150 + "handlers": ["console"], 151 + "propagate": False, 152 + }, 153 + }, 154 + } 155 + 156 + # Sentry 157 + # ------------------------------------------------------------------------------ 158 + SENTRY_DSN = env("SENTRY_DSN") 159 + SENTRY_LOG_LEVEL = env.int("DJANGO_SENTRY_LOG_LEVEL", logging.INFO) 160 + 161 + sentry_logging = LoggingIntegration( 162 + level=SENTRY_LOG_LEVEL, # Capture info and above as breadcrumbs 163 + event_level=logging.ERROR, # Send errors as events 164 + ) 165 + sentry_sdk.init(dsn=SENTRY_DSN, integrations=[sentry_logging, DjangoIntegration()]) 166 + 167 + # Your stuff... 168 + # ------------------------------------------------------------------------------
+51
config/settings/test.py
··· 1 + """ 2 + With these settings, tests run faster. 3 + """ 4 + 5 + from .base import * # noqa 6 + from .base import env 7 + 8 + # GENERAL 9 + # ------------------------------------------------------------------------------ 10 + # https://docs.djangoproject.com/en/dev/ref/settings/#secret-key 11 + SECRET_KEY = env( 12 + "DJANGO_SECRET_KEY", 13 + default="GlSRVXhTNJXx3Fnu5HUYlgeoMIXy3rl76CIhfOAEHtXE4jrGAEDbAWyzIpW7SVQn", 14 + ) 15 + # https://docs.djangoproject.com/en/dev/ref/settings/#test-runner 16 + TEST_RUNNER = "django.test.runner.DiscoverRunner" 17 + 18 + # CACHES 19 + # ------------------------------------------------------------------------------ 20 + # https://docs.djangoproject.com/en/dev/ref/settings/#caches 21 + CACHES = { 22 + "default": { 23 + "BACKEND": "django.core.cache.backends.locmem.LocMemCache", 24 + "LOCATION": "", 25 + } 26 + } 27 + 28 + # PASSWORDS 29 + # ------------------------------------------------------------------------------ 30 + # https://docs.djangoproject.com/en/dev/ref/settings/#password-hashers 31 + PASSWORD_HASHERS = ["django.contrib.auth.hashers.MD5PasswordHasher"] 32 + 33 + # TEMPLATES 34 + # ------------------------------------------------------------------------------ 35 + TEMPLATES[-1]["OPTIONS"]["loaders"] = [ # type: ignore[index] # noqa F405 36 + ( 37 + "django.template.loaders.cached.Loader", 38 + [ 39 + "django.template.loaders.filesystem.Loader", 40 + "django.template.loaders.app_directories.Loader", 41 + ], 42 + ) 43 + ] 44 + 45 + # EMAIL 46 + # ------------------------------------------------------------------------------ 47 + # https://docs.djangoproject.com/en/dev/ref/settings/#email-backend 48 + EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend" 49 + 50 + # Your stuff... 51 + # ------------------------------------------------------------------------------
+46
config/urls.py
··· 1 + from django.conf import settings 2 + from django.conf.urls.static import static 3 + from django.contrib import admin 4 + from django.urls import include, path 5 + from django.views import defaults as default_views 6 + from django.views.generic import TemplateView 7 + 8 + urlpatterns = [ 9 + path("", TemplateView.as_view(template_name="pages/home.html"), name="home"), 10 + path( 11 + "about/", TemplateView.as_view(template_name="pages/about.html"), name="about" 12 + ), 13 + # Django Admin, use {% url 'admin:index' %} 14 + path(settings.ADMIN_URL, admin.site.urls), 15 + # User management 16 + path("users/", include("care.users.urls", namespace="users")), 17 + path("accounts/", include("allauth.urls")), 18 + # Your stuff: custom urls includes go here 19 + ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) 20 + 21 + 22 + if settings.DEBUG: 23 + # This allows the error pages to be debugged during development, just visit 24 + # these url in browser to see how these error pages look like. 25 + urlpatterns += [ 26 + path( 27 + "400/", 28 + default_views.bad_request, 29 + kwargs={"exception": Exception("Bad Request!")}, 30 + ), 31 + path( 32 + "403/", 33 + default_views.permission_denied, 34 + kwargs={"exception": Exception("Permission Denied")}, 35 + ), 36 + path( 37 + "404/", 38 + default_views.page_not_found, 39 + kwargs={"exception": Exception("Page not Found")}, 40 + ), 41 + path("500/", default_views.server_error), 42 + ] 43 + if "debug_toolbar" in settings.INSTALLED_APPS: 44 + import debug_toolbar 45 + 46 + urlpatterns = [path("__debug__/", include(debug_toolbar.urls))] + urlpatterns
+39
config/wsgi.py
··· 1 + """ 2 + WSGI config for Care project. 3 + 4 + This module contains the WSGI application used by Django's development server 5 + and any production WSGI deployments. It should expose a module-level variable 6 + named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover 7 + this application via the ``WSGI_APPLICATION`` setting. 8 + 9 + Usually you will have the standard Django WSGI application here, but it also 10 + might make sense to replace the whole Django WSGI application with a custom one 11 + that later delegates to the Django one. For example, you could introduce WSGI 12 + middleware here, or combine a Django application with an application of another 13 + framework. 14 + 15 + """ 16 + import os 17 + import sys 18 + 19 + from django.core.wsgi import get_wsgi_application 20 + 21 + # This allows easy placement of apps within the interior 22 + # care directory. 23 + app_path = os.path.abspath( 24 + os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir) 25 + ) 26 + sys.path.append(os.path.join(app_path, "care")) 27 + # We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks 28 + # if running multiple sites in the same mod_wsgi process. To fix this, use 29 + # mod_wsgi daemon mode with each site in its own daemon process, or use 30 + # os.environ["DJANGO_SETTINGS_MODULE"] = "config.settings.production" 31 + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production") 32 + 33 + # This application object is used by any WSGI server configured to use this 34 + # file. This includes Django's development server, if the WSGI_APPLICATION 35 + # setting points here. 36 + application = get_wsgi_application() 37 + # Apply WSGI middleware here. 38 + # from helloworld.wsgi import HelloWorldApplication 39 + # application = HelloWorldApplication(application)
+20
docs/Makefile
··· 1 + # Minimal makefile for Sphinx documentation 2 + # 3 + 4 + # You can set these variables from the command line, and also 5 + # from the environment for the first two. 6 + SPHINXOPTS ?= 7 + SPHINXBUILD ?= sphinx-build 8 + SOURCEDIR = . 9 + BUILDDIR = _build 10 + 11 + # Put it first so that "make" without argument is like "make help". 12 + help: 13 + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 + 15 + .PHONY: help Makefile 16 + 17 + # Catch-all target: route all unknown targets to Sphinx using the new 18 + # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 + %: Makefile 20 + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+1
docs/__init__.py
··· 1 + # Included so that Django's startproject comment runs against the docs directory
+55
docs/conf.py
··· 1 + # Configuration file for the Sphinx documentation builder. 2 + # 3 + # This file only contains a selection of the most common options. For a full 4 + # list see the documentation: 5 + # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 + 7 + # -- Path setup -------------------------------------------------------------- 8 + 9 + # If extensions (or modules to document with autodoc) are in another directory, 10 + # add these directories to sys.path here. If the directory is relative to the 11 + # documentation root, use os.path.abspath to make it absolute, like shown here. 12 + # 13 + import os 14 + import sys 15 + 16 + # import django 17 + # sys.path.insert(0, os.path.abspath('..')) 18 + # os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local") 19 + # django.setup() 20 + 21 + 22 + # -- Project information ----------------------------------------------------- 23 + 24 + project = "Care" 25 + copyright = """2020, 👪""" 26 + author = "👪" 27 + 28 + 29 + # -- General configuration --------------------------------------------------- 30 + 31 + # Add any Sphinx extension module names here, as strings. They can be 32 + # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 33 + # ones. 34 + extensions = [] 35 + 36 + # Add any paths that contain templates here, relative to this directory. 37 + templates_path = ["_templates"] 38 + 39 + # List of patterns, relative to source directory, that match files and 40 + # directories to ignore when looking for source files. 41 + # This pattern also affects html_static_path and html_extra_path. 42 + exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] 43 + 44 + 45 + # -- Options for HTML output ------------------------------------------------- 46 + 47 + # The theme to use for HTML and HTML Help pages. See the documentation for 48 + # a list of builtin themes. 49 + # 50 + html_theme = "alabaster" 51 + 52 + # Add any paths that contain custom static files (such as style sheets) here, 53 + # relative to this directory. They are copied after the builtin static files, 54 + # so a file named "default.css" will overwrite the builtin "default.css". 55 + html_static_path = ["_static"]
+22
docs/index.rst
··· 1 + .. Care documentation master file, created by 2 + sphinx-quickstart. 3 + You can adapt this file completely to your liking, but it should at least 4 + contain the root `toctree` directive. 5 + 6 + Welcome to Care's documentation! 7 + ====================================================================== 8 + 9 + .. toctree:: 10 + :maxdepth: 2 11 + :caption: Contents: 12 + 13 + pycharm/configuration 14 + 15 + 16 + 17 + Indices and tables 18 + ================== 19 + 20 + * :ref:`genindex` 21 + * :ref:`modindex` 22 + * :ref:`search`
+35
docs/make.bat
··· 1 + @ECHO OFF 2 + 3 + pushd %~dp0 4 + 5 + REM Command file for Sphinx documentation 6 + 7 + if "%SPHINXBUILD%" == "" ( 8 + set SPHINXBUILD=sphinx-build 9 + ) 10 + set SOURCEDIR=. 11 + set BUILDDIR=_build 12 + 13 + if "%1" == "" goto help 14 + 15 + %SPHINXBUILD% >NUL 2>NUL 16 + if errorlevel 9009 ( 17 + echo. 18 + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 + echo.installed, then set the SPHINXBUILD environment variable to point 20 + echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 + echo.may add the Sphinx directory to PATH. 22 + echo. 23 + echo.If you don't have Sphinx installed, grab it from 24 + echo.http://sphinx-doc.org/ 25 + exit /b 1 26 + ) 27 + 28 + %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 + goto end 30 + 31 + :help 32 + %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 + 34 + :end 35 + popd
+70
docs/pycharm/configuration.rst
··· 1 + Docker Remote Debugging 2 + ======================= 3 + 4 + To connect to python remote interpreter inside docker, you have to make sure first, that Pycharm is aware of your docker. 5 + 6 + Go to *Settings > Build, Execution, Deployment > Docker*. If you are on linux, you can use docker directly using its socket `unix:///var/run/docker.sock`, if you are on Windows or Mac, make sure that you have docker-machine installed, then you can simply *Import credentials from Docker Machine*. 7 + 8 + .. image:: images/1.png 9 + 10 + Configure Remote Python Interpreter 11 + ----------------------------------- 12 + 13 + This repository comes with already prepared "Run/Debug Configurations" for docker. 14 + 15 + .. image:: images/2.png 16 + 17 + But as you can see, at the beginning there is something wrong with them. They have red X on django icon, and they cannot be used, without configuring remote python interpteter. To do that, you have to go to *Settings > Build, Execution, Deployment* first. 18 + 19 + 20 + Next, you have to add new remote python interpreter, based on already tested deployment settings. Go to *Settings > Project > Project Interpreter*. Click on the cog icon, and click *Add Remote*. 21 + 22 + .. image:: images/3.png 23 + 24 + Switch to *Docker Compose* and select `local.yml` file from directory of your project, next set *Service name* to `django` 25 + 26 + .. image:: images/4.png 27 + 28 + Having that, click *OK*. Close *Settings* panel, and wait few seconds... 29 + 30 + .. image:: images/7.png 31 + 32 + After few seconds, all *Run/Debug Configurations* should be ready to use. 33 + 34 + .. image:: images/8.png 35 + 36 + **Things you can do with provided configuration**: 37 + 38 + * run and debug python code 39 + 40 + .. image:: images/f1.png 41 + 42 + * run and debug tests 43 + 44 + .. image:: images/f2.png 45 + .. image:: images/f3.png 46 + 47 + * run and debug migrations or different django management commands 48 + 49 + .. image:: images/f4.png 50 + 51 + * and many others.. 52 + 53 + Known issues 54 + ------------ 55 + 56 + * Pycharm hangs on "Connecting to Debugger" 57 + 58 + .. image:: images/issue1.png 59 + 60 + This might be fault of your firewall. Take a look on this ticket - https://youtrack.jetbrains.com/issue/PY-18913 61 + 62 + * Modified files in `.idea` directory 63 + 64 + Most of the files from `.idea/` were added to `.gitignore` with a few exceptions, which were made, to provide "ready to go" configuration. After adding remote interpreter some of these files are altered by PyCharm: 65 + 66 + .. image:: images/issue2.png 67 + 68 + In theory you can remove them from repository, but then, other people will lose a ability to initialize a project from provided configurations as you did. To get rid of this annoying state, you can run command:: 69 + 70 + $ git update-index --assume-unchanged care.iml
docs/pycharm/images/1.png

This is a binary file and will not be displayed.

docs/pycharm/images/2.png

This is a binary file and will not be displayed.

docs/pycharm/images/3.png

This is a binary file and will not be displayed.

docs/pycharm/images/4.png

This is a binary file and will not be displayed.

docs/pycharm/images/7.png

This is a binary file and will not be displayed.

docs/pycharm/images/8.png

This is a binary file and will not be displayed.

docs/pycharm/images/f1.png

This is a binary file and will not be displayed.

docs/pycharm/images/f2.png

This is a binary file and will not be displayed.

docs/pycharm/images/f3.png

This is a binary file and will not be displayed.

docs/pycharm/images/f4.png

This is a binary file and will not be displayed.

docs/pycharm/images/issue1.png

This is a binary file and will not be displayed.

docs/pycharm/images/issue2.png

This is a binary file and will not be displayed.

+6
locale/README.rst
··· 1 + Translations 2 + ============ 3 + 4 + Translations will be placed in this folder when running:: 5 + 6 + python manage.py makemessages
+30
manage.py
··· 1 + #!/usr/bin/env python 2 + import os 3 + import sys 4 + 5 + if __name__ == "__main__": 6 + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local") 7 + 8 + try: 9 + from django.core.management import execute_from_command_line 10 + except ImportError: 11 + # The above import may fail for some other reason. Ensure that the 12 + # issue is really that Django is missing to avoid masking other 13 + # exceptions on Python 2. 14 + try: 15 + import django # noqa 16 + except ImportError: 17 + raise ImportError( 18 + "Couldn't import Django. Are you sure it's installed and " 19 + "available on your PYTHONPATH environment variable? Did you " 20 + "forget to activate a virtual environment?" 21 + ) 22 + 23 + raise 24 + 25 + # This allows easy placement of apps within the interior 26 + # care directory. 27 + current_path = os.path.dirname(os.path.abspath(__file__)) 28 + sys.path.append(os.path.join(current_path, "care")) 29 + 30 + execute_from_command_line(sys.argv)
+66
merge_production_dotenvs_in_dotenv.py
··· 1 + import os 2 + from typing import Sequence 3 + 4 + import pytest 5 + 6 + ROOT_DIR_PATH = os.path.dirname(os.path.realpath(__file__)) 7 + PRODUCTION_DOTENVS_DIR_PATH = os.path.join(ROOT_DIR_PATH, ".envs", ".production") 8 + PRODUCTION_DOTENV_FILE_PATHS = [ 9 + os.path.join(PRODUCTION_DOTENVS_DIR_PATH, ".django"), 10 + os.path.join(PRODUCTION_DOTENVS_DIR_PATH, ".postgres"), 11 + ] 12 + DOTENV_FILE_PATH = os.path.join(ROOT_DIR_PATH, ".env") 13 + 14 + 15 + def merge( 16 + output_file_path: str, merged_file_paths: Sequence[str], append_linesep: bool = True 17 + ) -> None: 18 + with open(output_file_path, "w") as output_file: 19 + for merged_file_path in merged_file_paths: 20 + with open(merged_file_path, "r") as merged_file: 21 + merged_file_content = merged_file.read() 22 + output_file.write(merged_file_content) 23 + if append_linesep: 24 + output_file.write(os.linesep) 25 + 26 + 27 + def main(): 28 + merge(DOTENV_FILE_PATH, PRODUCTION_DOTENV_FILE_PATHS) 29 + 30 + 31 + @pytest.mark.parametrize("merged_file_count", range(3)) 32 + @pytest.mark.parametrize("append_linesep", [True, False]) 33 + def test_merge(tmpdir_factory, merged_file_count: int, append_linesep: bool): 34 + tmp_dir_path = str(tmpdir_factory.getbasetemp()) 35 + 36 + output_file_path = os.path.join(tmp_dir_path, ".env") 37 + 38 + expected_output_file_content = "" 39 + merged_file_paths = [] 40 + for i in range(merged_file_count): 41 + merged_file_ord = i + 1 42 + 43 + merged_filename = ".service{}".format(merged_file_ord) 44 + merged_file_path = os.path.join(tmp_dir_path, merged_filename) 45 + 46 + merged_file_content = merged_filename * merged_file_ord 47 + 48 + with open(merged_file_path, "w+") as file: 49 + file.write(merged_file_content) 50 + 51 + expected_output_file_content += merged_file_content 52 + if append_linesep: 53 + expected_output_file_content += os.linesep 54 + 55 + merged_file_paths.append(merged_file_path) 56 + 57 + merge(output_file_path, merged_file_paths, append_linesep) 58 + 59 + with open(output_file_path, "r") as output_file: 60 + actual_output_file_content = output_file.read() 61 + 62 + assert actual_output_file_content == expected_output_file_content 63 + 64 + 65 + if __name__ == "__main__": 66 + main()
+3
pytest.ini
··· 1 + [pytest] 2 + addopts = --ds=config.settings.test --reuse-db 3 + python_files = tests.py test_*.py
+3
requirements.txt
··· 1 + # This file is expected by Heroku. 2 + 3 + -r requirements/production.txt
+15
requirements/base.txt
··· 1 + pytz==2019.3 # https://github.com/stub42/pytz 2 + python-slugify==4.0.0 # https://github.com/un33k/python-slugify 3 + Pillow==7.0.0 # https://github.com/python-pillow/Pillow 4 + argon2-cffi==19.2.0 # https://github.com/hynek/argon2_cffi 5 + whitenoise==5.0.1 # https://github.com/evansd/whitenoise 6 + redis==3.4.1 # https://github.com/andymccurdy/redis-py 7 + 8 + # Django 9 + # ------------------------------------------------------------------------------ 10 + django==2.2.11 # pyup: < 3.0 # https://www.djangoproject.com/ 11 + django-environ==0.4.5 # https://github.com/joke2k/django-environ 12 + django-model-utils==4.0.0 # https://github.com/jazzband/django-model-utils 13 + django-allauth==0.41.0 # https://github.com/pennersr/django-allauth 14 + django-crispy-forms==1.9.0 # https://github.com/django-crispy-forms/django-crispy-forms 15 + django-redis==4.11.0 # https://github.com/niwinz/django-redis
+31
requirements/local.txt
··· 1 + -r ./base.txt 2 + 3 + Werkzeug==1.0.0 # https://github.com/pallets/werkzeug 4 + ipdb==0.13.2 # https://github.com/gotcha/ipdb 5 + Sphinx==2.4.4 # https://github.com/sphinx-doc/sphinx 6 + psycopg2-binary==2.8.4 # https://github.com/psycopg/psycopg2 7 + 8 + # Testing 9 + # ------------------------------------------------------------------------------ 10 + mypy==0.770 # https://github.com/python/mypy 11 + django-stubs==1.5.0 # https://github.com/typeddjango/django-stubs 12 + pytest==5.3.5 # https://github.com/pytest-dev/pytest 13 + pytest-sugar==0.9.2 # https://github.com/Frozenball/pytest-sugar 14 + 15 + # Code quality 16 + # ------------------------------------------------------------------------------ 17 + flake8==3.7.9 # https://github.com/PyCQA/flake8 18 + flake8-isort==2.9.0 # https://github.com/gforcada/flake8-isort 19 + coverage==5.0.4 # https://github.com/nedbat/coveragepy 20 + black==19.10b0 # https://github.com/ambv/black 21 + pylint-django==2.0.14 # https://github.com/PyCQA/pylint-django 22 + pre-commit==2.2.0 # https://github.com/pre-commit/pre-commit 23 + 24 + # Django 25 + # ------------------------------------------------------------------------------ 26 + factory-boy==2.12.0 # https://github.com/FactoryBoy/factory_boy 27 + 28 + django-debug-toolbar==2.2 # https://github.com/jazzband/django-debug-toolbar 29 + django-extensions==2.2.8 # https://github.com/django-extensions/django-extensions 30 + django-coverage-plugin==1.8.0 # https://github.com/nedbat/django_coverage_plugin 31 + pytest-django==3.8.0 # https://github.com/pytest-dev/pytest-django
+11
requirements/production.txt
··· 1 + # PRECAUTION: avoid production dependencies that aren't in development 2 + 3 + -r ./base.txt 4 + 5 + gunicorn==20.0.4 # https://github.com/benoitc/gunicorn 6 + psycopg2==2.8.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2 7 + sentry-sdk==0.14.2 # https://github.com/getsentry/sentry-python 8 + 9 + # Django 10 + # ------------------------------------------------------------------------------ 11 + django-anymail[mailgun]==7.0.0 # https://github.com/anymail/django-anymail
+1
runtime.txt
··· 1 + python-3.7.6
+23
setup.cfg
··· 1 + [flake8] 2 + max-line-length = 120 3 + exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules 4 + 5 + [pycodestyle] 6 + max-line-length = 120 7 + exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules 8 + 9 + [mypy] 10 + python_version = 3.7 11 + check_untyped_defs = True 12 + ignore_missing_imports = True 13 + warn_unused_ignores = True 14 + warn_redundant_casts = True 15 + warn_unused_configs = True 16 + plugins = mypy_django_plugin.main 17 + 18 + [mypy.plugins.django-stubs] 19 + django_settings_module = config.settings.test 20 + 21 + [mypy-*.migrations.*] 22 + # Django migrations should not produce any errors: 23 + ignore_errors = True
+96
utility/install_os_dependencies.sh
··· 1 + #!/bin/bash 2 + 3 + WORK_DIR="$(dirname "$0")" 4 + DISTRO_NAME=$(lsb_release -sc) 5 + OS_REQUIREMENTS_FILENAME="requirements-$DISTRO_NAME.apt" 6 + 7 + cd $WORK_DIR 8 + 9 + # Check if a requirements file exist for the current distribution. 10 + if [ ! -r "$OS_REQUIREMENTS_FILENAME" ]; then 11 + cat <<-EOF >&2 12 + There is no requirements file for your distribution. 13 + You can see one of the files listed below to help search the equivalent package in your system: 14 + $(find ./ -name "requirements-*.apt" -printf " - %f\n") 15 + EOF 16 + exit 1; 17 + fi 18 + 19 + # Handle call with wrong command 20 + function wrong_command() 21 + { 22 + echo "${0##*/} - unknown command: '${1}'" >&2 23 + usage_message 24 + } 25 + 26 + # Print help / script usage 27 + function usage_message() 28 + { 29 + cat <<-EOF 30 + Usage: $WORK_DIR/${0##*/} <command> 31 + Available commands are: 32 + list Print a list of all packages defined on ${OS_REQUIREMENTS_FILENAME} file 33 + help Print this help 34 + 35 + Commands that require superuser permission: 36 + install Install packages defined on ${OS_REQUIREMENTS_FILENAME} file. Note: This 37 + does not upgrade the packages already installed for new versions, even if 38 + new version is available in the repository. 39 + upgrade Same that install, but upgrade the already installed packages, if new 40 + version is available. 41 + EOF 42 + } 43 + 44 + # Read the requirements.apt file, and remove comments and blank lines 45 + function list_packages(){ 46 + grep -v "#" "${OS_REQUIREMENTS_FILENAME}" | grep -v "^$"; 47 + } 48 + 49 + function install_packages() 50 + { 51 + list_packages | xargs apt-get --no-upgrade install -y; 52 + } 53 + 54 + function upgrade_packages() 55 + { 56 + list_packages | xargs apt-get install -y; 57 + } 58 + 59 + function install_or_upgrade() 60 + { 61 + P=${1} 62 + PARAN=${P:-"install"} 63 + 64 + if [[ $EUID -ne 0 ]]; then 65 + cat <<-EOF >&2 66 + You must run this script with root privilege 67 + Please do: 68 + sudo $WORK_DIR/${0##*/} $PARAN 69 + EOF 70 + exit 1 71 + else 72 + 73 + apt-get update 74 + 75 + # Install the basic compilation dependencies and other required libraries of this project 76 + if [ "$PARAN" == "install" ]; then 77 + install_packages; 78 + else 79 + upgrade_packages; 80 + fi 81 + 82 + # cleaning downloaded packages from apt-get cache 83 + apt-get clean 84 + 85 + exit 0 86 + fi 87 + } 88 + 89 + # Handle command argument 90 + case "$1" in 91 + install) install_or_upgrade;; 92 + upgrade) install_or_upgrade "upgrade";; 93 + list) list_packages;; 94 + help|"") usage_message;; 95 + *) wrong_command "$1";; 96 + esac
+39
utility/install_python_dependencies.sh
··· 1 + #!/bin/bash 2 + 3 + WORK_DIR="$(dirname "$0")" 4 + PROJECT_DIR="$(dirname "$WORK_DIR")" 5 + 6 + pip --version >/dev/null 2>&1 || { 7 + echo >&2 -e "\npip is required but it's not installed." 8 + echo >&2 -e "You can install it by running the following command:\n" 9 + echo >&2 "wget https://bootstrap.pypa.io/get-pip.py --output-document=get-pip.py; chmod +x get-pip.py; sudo -H python3 get-pip.py" 10 + echo >&2 -e "\n" 11 + echo >&2 -e "\nFor more information, see pip documentation: https://pip.pypa.io/en/latest/" 12 + exit 1; 13 + } 14 + 15 + virtualenv --version >/dev/null 2>&1 || { 16 + echo >&2 -e "\nvirtualenv is required but it's not installed." 17 + echo >&2 -e "You can install it by running the following command:\n" 18 + echo >&2 "sudo -H pip3 install virtualenv" 19 + echo >&2 -e "\n" 20 + echo >&2 -e "\nFor more information, see virtualenv documentation: https://virtualenv.pypa.io/en/latest/" 21 + exit 1; 22 + } 23 + 24 + if [ -z "$VIRTUAL_ENV" ]; then 25 + echo >&2 -e "\nYou need activate a virtualenv first" 26 + echo >&2 -e 'If you do not have a virtualenv created, run the following command to create and automatically activate a new virtualenv named "venv" on current folder:\n' 27 + echo >&2 -e "virtualenv venv --python=\`which python3\`" 28 + echo >&2 -e "\nTo leave/disable the currently active virtualenv, run the following command:\n" 29 + echo >&2 "deactivate" 30 + echo >&2 -e "\nTo activate the virtualenv again, run the following command:\n" 31 + echo >&2 "source venv/bin/activate" 32 + echo >&2 -e "\nFor more information, see virtualenv documentation: https://virtualenv.pypa.io/en/latest/" 33 + echo >&2 -e "\n" 34 + exit 1; 35 + else 36 + 37 + pip install -r $PROJECT_DIR/requirements/local.txt 38 + pip install -r $PROJECT_DIR/requirements.txt 39 + fi
+23
utility/requirements-bionic.apt
··· 1 + ##basic build dependencies of various Django apps for Ubuntu Bionic 18.04 2 + #build-essential metapackage install: make, gcc, g++, 3 + build-essential 4 + #required to translate 5 + gettext 6 + python3-dev 7 + 8 + ##shared dependencies of: 9 + ##Pillow, pylibmc 10 + zlib1g-dev 11 + 12 + ##Postgresql and psycopg2 dependencies 13 + libpq-dev 14 + 15 + ##Pillow dependencies 16 + libtiff5-dev 17 + libjpeg8-dev 18 + libfreetype6-dev 19 + liblcms2-dev 20 + libwebp-dev 21 + 22 + ##django-extensions 23 + libgraphviz-dev
+23
utility/requirements-buster.apt
··· 1 + ##basic build dependencies of various Django apps for Debian Jessie 10.x 2 + #build-essential metapackage install: make, gcc, g++, 3 + build-essential 4 + #required to translate 5 + gettext 6 + python3-dev 7 + 8 + ##shared dependencies of: 9 + ##Pillow, pylibmc 10 + zlib1g-dev 11 + 12 + ##Postgresql and psycopg2 dependencies 13 + libpq-dev 14 + 15 + ##Pillow dependencies 16 + libtiff5-dev 17 + libjpeg62-turbo-dev 18 + libfreetype6-dev 19 + liblcms2-dev 20 + libwebp-dev 21 + 22 + ##django-extensions 23 + libgraphviz-dev
+23
utility/requirements-jessie.apt
··· 1 + ##basic build dependencies of various Django apps for Debian Jessie 8.x 2 + #build-essential metapackage install: make, gcc, g++, 3 + build-essential 4 + #required to translate 5 + gettext 6 + python3-dev 7 + 8 + ##shared dependencies of: 9 + ##Pillow, pylibmc 10 + zlib1g-dev 11 + 12 + ##Postgresql and psycopg2 dependencies 13 + libpq-dev 14 + 15 + ##Pillow dependencies 16 + libtiff5-dev 17 + libjpeg62-turbo-dev 18 + libfreetype6-dev 19 + liblcms2-dev 20 + libwebp-dev 21 + 22 + ##django-extensions 23 + graphviz-dev
+23
utility/requirements-stretch.apt
··· 1 + ##basic build dependencies of various Django apps for Debian Jessie 9.x 2 + #build-essential metapackage install: make, gcc, g++, 3 + build-essential 4 + #required to translate 5 + gettext 6 + python3-dev 7 + 8 + ##shared dependencies of: 9 + ##Pillow, pylibmc 10 + zlib1g-dev 11 + 12 + ##Postgresql and psycopg2 dependencies 13 + libpq-dev 14 + 15 + ##Pillow dependencies 16 + libtiff5-dev 17 + libjpeg62-turbo-dev 18 + libfreetype6-dev 19 + liblcms2-dev 20 + libwebp-dev 21 + 22 + ##django-extensions 23 + graphviz-dev
+23
utility/requirements-trusty.apt
··· 1 + ##basic build dependencies of various Django apps for Ubuntu Trusty 14.04 2 + #build-essential metapackage install: make, gcc, g++, 3 + build-essential 4 + #required to translate 5 + gettext 6 + python3-dev 7 + 8 + ##shared dependencies of: 9 + ##Pillow, pylibmc 10 + zlib1g-dev 11 + 12 + ##Postgresql and psycopg2 dependencies 13 + libpq-dev 14 + 15 + ##Pillow dependencies 16 + libtiff4-dev 17 + libjpeg8-dev 18 + libfreetype6-dev 19 + liblcms1-dev 20 + libwebp-dev 21 + 22 + ##django-extensions 23 + graphviz-dev
+23
utility/requirements-xenial.apt
··· 1 + ##basic build dependencies of various Django apps for Ubuntu Xenial 16.04 2 + #build-essential metapackage install: make, gcc, g++, 3 + build-essential 4 + #required to translate 5 + gettext 6 + python3-dev 7 + 8 + ##shared dependencies of: 9 + ##Pillow, pylibmc 10 + zlib1g-dev 11 + 12 + ##Postgresql and psycopg2 dependencies 13 + libpq-dev 14 + 15 + ##Pillow dependencies 16 + libtiff5-dev 17 + libjpeg8-dev 18 + libfreetype6-dev 19 + liblcms2-dev 20 + libwebp-dev 21 + 22 + ##django-extensions 23 + graphviz-dev