diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index ee42e63..0000000 --- a/.coveragerc +++ /dev/null @@ -1,5 +0,0 @@ -[run] -include = geeksbot_v2/* -omit = *migrations*, *tests* -plugins = - django_coverage_plugin diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index e63c0c1..0000000 --- a/.dockerignore +++ /dev/null @@ -1,4 +0,0 @@ -.* -!.coveragerc -!.env -!.pylintrc diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index a4eb1d5..0000000 --- a/.editorconfig +++ /dev/null @@ -1,33 +0,0 @@ -# http://editorconfig.org - -root = true - -[*] -charset = utf-8 -end_of_line = lf -insert_final_newline = true -trim_trailing_whitespace = true - -[*.{py,rst,ini}] -indent_style = space -indent_size = 4 - -[*.py] -line_length=120 -known_first_party=geeksbot_v2 -multi_line_output=3 -default_section=THIRDPARTY - -[*.{html,css,scss,json,yml}] -indent_style = space -indent_size = 2 - -[*.md] -trim_trailing_whitespace = false - -[Makefile] -indent_style = tab - -[nginx.conf] -indent_style = space -indent_size = 2 diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 176a458..0000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -* text=auto diff --git a/.pylintrc b/.pylintrc deleted file mode 100644 index e0faac0..0000000 --- a/.pylintrc +++ /dev/null @@ -1,14 +0,0 @@ -[MASTER] -load-plugins=pylint_django - -[FORMAT] -max-line-length=120 - -[MESSAGES CONTROL] -disable=missing-docstring,invalid-name - -[DESIGN] -max-parents=13 - -[TYPECHECK] -generated-members=REQUEST,acl_users,aq_parent,"[a-zA-Z]+_set{1,2}",save,delete diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index e9d3c8e..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "python.pythonPath": "/home/dustyp/.virtualenvs/geeksbot/bin/python" -} \ No newline at end of file diff --git a/services/Dockerfile-base b/Dockerfile similarity index 75% rename from services/Dockerfile-base rename to Dockerfile index f2b0e0a..96878e4 100644 --- a/services/Dockerfile-base +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.7-alpine AS geeksbot-base +FROM python:3.8-alpine AS geeksbot ENV DEBIAN_FRONTEND noninteractive ENV PYTHONUNBUFFERED 1 @@ -27,4 +27,15 @@ ENV LANG C.UTF-8 RUN pip install --upgrade pip RUN pip install virtualenv -RUN apk update && apk add postgresql-client +WORKDIR /code + +COPY requirements/base.txt . +COPY requirements/production.txt . +COPY requirements/geeksbot.txt . +COPY .env . +COPY entrypoint . + +RUN pip install -r production.txt +RUN pip install -r geeksbot.txt + +CMD ["./entrypoint"] diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index 1283d7e..0000000 --- a/docs/Makefile +++ /dev/null @@ -1,153 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = _build - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - -rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/geeksbot_v2.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/geeksbot_v2.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/geeksbot_v2" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/geeksbot_v2" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." diff --git a/docs/__init__.py b/docs/__init__.py deleted file mode 100644 index 8772c82..0000000 --- a/docs/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Included so that Django's startproject comment runs against the docs directory diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index e9bc49e..0000000 --- a/docs/conf.py +++ /dev/null @@ -1,255 +0,0 @@ -# geeksbot documentation build configuration file, created by -# sphinx-quickstart. -# -# This file is execfile()d with the current directory set to its containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import os -import sys - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ----------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = [] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ["_templates"] - -# The suffix of source filenames. -source_suffix = ".rst" - -# The encoding of source files. -# source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = "index" - -# General information about the project. -project = "geeksbot" -copyright = """2019, Dustin Pianalto""" - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = "0.1" -# The full version, including alpha/beta/rc tags. -release = "0.1" - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -# today = '' -# Else, today_fmt is used as the format for a strftime call. -# today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ["_build"] - -# The reST default role (used for this markup: `text`) to use for all documents. -# default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -# add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -# add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -# show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = "sphinx" - -# A list of ignored prefixes for module index sorting. -# modindex_common_prefix = [] - - -# -- Options for HTML output --------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = "default" - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -# html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -# html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -# html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -# html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -# html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ["_static"] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -# html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -# html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -# html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -# html_additional_pages = {} - -# If false, no module index is generated. -# html_domain_indices = True - -# If false, no index is generated. -# html_use_index = True - -# If true, the index is split into individual pages for each letter. -# html_split_index = False - -# If true, links to the reST sources are added to the pages. -# html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -# html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -# html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -# html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -# html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = "geeksbot_v2doc" - - -# -- Options for LaTeX output -------------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). - # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. - # 'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]). -latex_documents = [ - ( - "index", - "geeksbot_v2.tex", - "geeksbot Documentation", - """Dustin Pianalto""", - "manual", - ) -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -# latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -# latex_use_parts = False - -# If true, show page references after internal links. -# latex_show_pagerefs = False - -# If true, show URL addresses after external links. -# latex_show_urls = False - -# Documents to append as an appendix to all manuals. -# latex_appendices = [] - -# If false, no module index is generated. -# latex_domain_indices = True - - -# -- Options for manual page output -------------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ( - "index", - "geeksbot_v2", - "geeksbot Documentation", - ["""Dustin Pianalto"""], - 1, - ) -] - -# If true, show URL addresses after external links. -# man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------------ - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ( - "index", - "geeksbot_v2", - "geeksbot Documentation", - """Dustin Pianalto""", - "geeksbot", - """Version 2 of Geeksbot""", - "Miscellaneous", - ) -] - -# Documents to append as an appendix to all manuals. -# texinfo_appendices = [] - -# If false, no module index is generated. -# texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -# texinfo_show_urls = 'footnote' diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index a594db1..0000000 --- a/docs/index.rst +++ /dev/null @@ -1,20 +0,0 @@ -.. geeksbot documentation master file, created by - sphinx-quickstart. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -geeksbot Project Documentation -==================================================================== - -Table of Contents: - -.. toctree:: - :maxdepth: 2 - - -Indices & Tables -================ - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index a5da73c..0000000 --- a/docs/make.bat +++ /dev/null @@ -1,190 +0,0 @@ -@ECHO OFF - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set BUILDDIR=_build -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . -set I18NSPHINXOPTS=%SPHINXOPTS% . -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% - set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. singlehtml to make a single large HTML file - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. text to make text files - echo. man to make manual pages - echo. texinfo to make Texinfo files - echo. gettext to make PO message catalogs - echo. changes to make an overview over all changed/added/deprecated items - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end -) - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\geeksbot_v2.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\geeksbot_v2.ghc - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The text files are in %BUILDDIR%/text. - goto end -) - -if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The manual pages are in %BUILDDIR%/man. - goto end -) - -if "%1" == "texinfo" ( - %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. - goto end -) - -if "%1" == "gettext" ( - %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The message catalogs are in %BUILDDIR%/locale. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - if errorlevel 1 exit /b 1 - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - if errorlevel 1 exit /b 1 - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - if errorlevel 1 exit /b 1 - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -:end diff --git a/docs/pycharm/configuration.rst b/docs/pycharm/configuration.rst deleted file mode 100644 index 79a3fb4..0000000 --- a/docs/pycharm/configuration.rst +++ /dev/null @@ -1,64 +0,0 @@ -Docker Remote Debugging -======================= - -To connect to python remote interpreter inside docker, you have to make sure first, that Pycharm is aware of your docker. - -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*. - -.. image:: images/1.png - -Configure Remote Python Interpreter ------------------------------------ - -This repository comes with already prepared "Run/Debug Configurations" for docker. - -.. image:: images/2.png - -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. - - -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*. - -.. image:: images/3.png - -Switch to *Docker Compose* and select `local.yml` file from directory of your project, next set *Service name* to `django` - -.. image:: images/4.png - -Having that, click *OK*. Close *Settings* panel, and wait few seconds... - -.. image:: images/7.png - -After few seconds, all *Run/Debug Configurations* should be ready to use. - -.. image:: images/8.png - -**Things you can do with provided configuration**: - -* run and debug python code -.. image:: images/f1.png -* run and debug tests -.. image:: images/f2.png -.. image:: images/f3.png -* run and debug migrations or different django management commands -.. image:: images/f4.png -* and many others.. - -Known issues ------------- - -* Pycharm hangs on "Connecting to Debugger" - -.. image:: images/issue1.png - -This might be fault of your firewall. Take a look on this ticket - https://youtrack.jetbrains.com/issue/PY-18913 - -* Modified files in `.idea` directory - -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: - -.. image:: images/issue2.png - -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:: - - $ git update-index --assume-unchanged geeksbot_v2.iml diff --git a/docs/pycharm/images/1.png b/docs/pycharm/images/1.png deleted file mode 100644 index 06908a1..0000000 Binary files a/docs/pycharm/images/1.png and /dev/null differ diff --git a/docs/pycharm/images/2.png b/docs/pycharm/images/2.png deleted file mode 100644 index 1fb8cf1..0000000 Binary files a/docs/pycharm/images/2.png and /dev/null differ diff --git a/docs/pycharm/images/3.png b/docs/pycharm/images/3.png deleted file mode 100644 index 32c9335..0000000 Binary files a/docs/pycharm/images/3.png and /dev/null differ diff --git a/docs/pycharm/images/4.png b/docs/pycharm/images/4.png deleted file mode 100644 index cf07f9d..0000000 Binary files a/docs/pycharm/images/4.png and /dev/null differ diff --git a/docs/pycharm/images/7.png b/docs/pycharm/images/7.png deleted file mode 100644 index 4f8807e..0000000 Binary files a/docs/pycharm/images/7.png and /dev/null differ diff --git a/docs/pycharm/images/8.png b/docs/pycharm/images/8.png deleted file mode 100644 index 05946f2..0000000 Binary files a/docs/pycharm/images/8.png and /dev/null differ diff --git a/docs/pycharm/images/f1.png b/docs/pycharm/images/f1.png deleted file mode 100644 index 2d8c4b6..0000000 Binary files a/docs/pycharm/images/f1.png and /dev/null differ diff --git a/docs/pycharm/images/f2.png b/docs/pycharm/images/f2.png deleted file mode 100644 index b123a47..0000000 Binary files a/docs/pycharm/images/f2.png and /dev/null differ diff --git a/docs/pycharm/images/f3.png b/docs/pycharm/images/f3.png deleted file mode 100644 index 713ab54..0000000 Binary files a/docs/pycharm/images/f3.png and /dev/null differ diff --git a/docs/pycharm/images/f4.png b/docs/pycharm/images/f4.png deleted file mode 100644 index 11668ec..0000000 Binary files a/docs/pycharm/images/f4.png and /dev/null differ diff --git a/docs/pycharm/images/issue1.png b/docs/pycharm/images/issue1.png deleted file mode 100644 index 1bb68ee..0000000 Binary files a/docs/pycharm/images/issue1.png and /dev/null differ diff --git a/docs/pycharm/images/issue2.png b/docs/pycharm/images/issue2.png deleted file mode 100644 index 174f6fd..0000000 Binary files a/docs/pycharm/images/issue2.png and /dev/null differ diff --git a/entrypoint b/entrypoint new file mode 100644 index 0000000..ea889bd --- /dev/null +++ b/entrypoint @@ -0,0 +1,13 @@ +#!/bin/sh + +set -o errexit +set -o pipefail +set -o nounset + +source .env + +# Check Redis is up + +# Check Web API is up with simple curl of hostcheck + +python -m geeksbot \ No newline at end of file diff --git a/geeksbot_v2/__init__.py b/geeksbot_v2/__init__.py deleted file mode 100644 index 055908f..0000000 --- a/geeksbot_v2/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -__version__ = "2.0.0" -__version_info__ = tuple( - [ - int(num) if num.isdigit() else num - for num in __version__.replace("-", ".", 1).split(".") - ] -) diff --git a/geeksbot_v2/channels/__init__.py b/geeksbot_v2/channels/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/geeksbot_v2/channels/admin.py b/geeksbot_v2/channels/admin.py deleted file mode 100644 index 8c38f3f..0000000 --- a/geeksbot_v2/channels/admin.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/geeksbot_v2/channels/api_urls.py b/geeksbot_v2/channels/api_urls.py deleted file mode 100644 index 63a1fdf..0000000 --- a/geeksbot_v2/channels/api_urls.py +++ /dev/null @@ -1,10 +0,0 @@ -from django.urls import path - -from .views import ChannelsAPI, ChannelDetail, AdminChannelAPI - -app_name = "channels_api" -urlpatterns = [ - path("", view=ChannelsAPI.as_view(), name="list"), - path("/", view=ChannelDetail.as_view(), name='detail'), - path("/admin/", view=AdminChannelAPI.as_view(), name='admin') -] diff --git a/geeksbot_v2/channels/apps.py b/geeksbot_v2/channels/apps.py deleted file mode 100644 index ebbced1..0000000 --- a/geeksbot_v2/channels/apps.py +++ /dev/null @@ -1,7 +0,0 @@ -from django.apps import AppConfig -from django.utils.translation import gettext_lazy as _ - - -class ChannelsConfig(AppConfig): - name = 'geeksbot_v2.channels' - verbose_name = _("Channels") diff --git a/geeksbot_v2/channels/migrations/0001_initial.py b/geeksbot_v2/channels/migrations/0001_initial.py deleted file mode 100644 index e1a6387..0000000 --- a/geeksbot_v2/channels/migrations/0001_initial.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 2.2.4 on 2019-09-20 21:39 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('guilds', '0001_initial'), - ] - - operations = [ - migrations.CreateModel( - name='Channel', - fields=[ - ('id', models.CharField(max_length=30, primary_key=True, serialize=False)), - ('guild', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='guilds.Guild')), - ], - ), - ] diff --git a/geeksbot_v2/channels/migrations/0002_auto_20190921_0250.py b/geeksbot_v2/channels/migrations/0002_auto_20190921_0250.py deleted file mode 100644 index b2cef5a..0000000 --- a/geeksbot_v2/channels/migrations/0002_auto_20190921_0250.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 2.2.4 on 2019-09-21 02:50 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('channels', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='channel', - name='admin', - field=models.BooleanField(default=False), - ), - migrations.AddField( - model_name='channel', - name='default', - field=models.BooleanField(default=False), - ), - migrations.AddField( - model_name='channel', - name='new_patron', - field=models.BooleanField(default=False), - ), - ] diff --git a/geeksbot_v2/channels/migrations/__init__.py b/geeksbot_v2/channels/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/geeksbot_v2/channels/models.py b/geeksbot_v2/channels/models.py deleted file mode 100644 index 244c603..0000000 --- a/geeksbot_v2/channels/models.py +++ /dev/null @@ -1,85 +0,0 @@ -from django.db import models -from django.core.exceptions import ObjectDoesNotExist -from rest_framework import status - -from geeksbot_v2.guilds.models import Guild -from .utils import create_error_response -from .utils import create_success_response - -# Create your models here. - - -class Channel(models.Model): - id = models.CharField(max_length=30, primary_key=True) - guild = models.ForeignKey(Guild, on_delete=models.CASCADE) - default = models.BooleanField(default=False) - new_patron = models.BooleanField(default=False) - admin = models.BooleanField(default=False) - - def update_channel(self, data): - if data.get('default'): - try: - existing_default = self.get_guild_channels(self.guild).get(default=True) - except ObjectDoesNotExist: - pass - else: - existing_default.default = False - existing_default.save() - finally: - self.default = data.get('default') - if data.get('new_patron'): - self.new_patron = data.get('new_patron') - if data.get('admin'): - self.admin = data.get('admin') - - self.save() - return self - - @classmethod - def add_new_channel(cls, data): - id = data.get('id') - if id and cls.get_channel_by_id(id): - return create_error_response('Channel Already Exists', - status=status.HTTP_409_CONFLICT) - guild_id = data.get('guild') - if not (id and guild_id): - return create_error_response('ID and Guild are required', - status=status.HTTP_400_BAD_REQUEST) - guild = Guild.get_guild_by_id(guild_id) - if not isinstance(guild, Guild): - return create_error_response('Guild Does Not Exist', - status=status.HTTP_404_NOT_FOUND) - - channel = cls( - id=id, - guild=guild, - default=data.get('default', False), - new_patron=data.get('new_patron', False), - admin=data.get('admin', False) - ) - channel.save() - return create_success_response(channel, status.HTTP_201_CREATED, many=False) - - @classmethod - def get_channel_by_id(cls, guild_id, channel_id): - try: - return cls.get_guild_channels(guild_id).get(id=channel_id) - except ObjectDoesNotExist: - return None - - @classmethod - def get_guild_channels(cls, guild): - if isinstance(guild, Guild): - return cls.objects.filter(guild=guild) - elif isinstance(guild, (str, int)): - return cls.objects.filter(guild__id=guild) - - @classmethod - def get_admin_channel(cls, guild_id): - try: - return cls.get_guild_channels(guild_id).get(admin=True) - except ObjectDoesNotExist: - return None - - def __str__(self): - return str(id) diff --git a/geeksbot_v2/channels/serializers.py b/geeksbot_v2/channels/serializers.py deleted file mode 100644 index 81af17b..0000000 --- a/geeksbot_v2/channels/serializers.py +++ /dev/null @@ -1,9 +0,0 @@ -from rest_framework import serializers - -from .models import Channel - - -class ChannelSerializer(serializers.ModelSerializer): - class Meta: - model = Channel - fields = "__all__" diff --git a/geeksbot_v2/channels/tests.py b/geeksbot_v2/channels/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/geeksbot_v2/channels/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/geeksbot_v2/channels/utils.py b/geeksbot_v2/channels/utils.py deleted file mode 100644 index 11fe383..0000000 --- a/geeksbot_v2/channels/utils.py +++ /dev/null @@ -1,14 +0,0 @@ -from rest_framework.response import Response -from rest_framework import status - - -def create_error_response(msg, status=status.HTTP_404_NOT_FOUND): - return Response({'details': msg}, - status=status) - - -def create_success_response(channel_data, status, many: bool = False): - from .serializers import ChannelSerializer - - return Response(ChannelSerializer(channel_data, many=many).data, - status=status) diff --git a/geeksbot_v2/channels/views.py b/geeksbot_v2/channels/views.py deleted file mode 100644 index ded5d42..0000000 --- a/geeksbot_v2/channels/views.py +++ /dev/null @@ -1,97 +0,0 @@ -from rest_framework.views import APIView -from rest_framework import status -from rest_framework.permissions import IsAuthenticated -from django.core.exceptions import ObjectDoesNotExist - -from geeksbot_v2.utils.api_utils import PaginatedAPIView -from .models import Channel -from .utils import create_error_response -from .utils import create_success_response - -# Create your views here. - -# API Views - - -class ChannelsAPI(PaginatedAPIView): - permission_classes = [IsAuthenticated] - - def get(self, request, guild_id, format=None): - channels = Channel.get_guild_channels(guild_id) - page = self.paginate_queryset(channels) - if page is not None: - return create_success_response(page, status.HTTP_200_OK, many=True) - - return create_success_response(channels, status.HTTP_200_OK, many=True) - - def post(self, request, format=None): - data = dict(request.data) - return Channel.add_new_channel(data) - - -class AdminChannelAPI(APIView): - permission_classes = [IsAuthenticated] - - def get(self, request, guild_id, format=None): - channel = Channel.get_admin_channel(guild_id) - if channel: - return create_success_response(channel, status=status.HTTP_200_OK) - return create_error_response('There is no admin channel configured for that guild', - status=status.HTTP_404_NOT_FOUND) - - def put(self, request, guild_id, format=None): - data = dict(request.data) - channel = Channel.get_channel_by_id(guild_id, data['channel']) - if channel: - channel = channel.update_channel({'admin': True}) - return create_success_response(channel, status=status.HTTP_202_ACCEPTED) - return create_error_response("That channel does not exist", - status=status.HTTP_404_NOT_FOUND) - - def delete(self, request, guild_id, format=None): - channel = Channel.get_admin_channel(guild_id) - if channel: - channel = channel.update_channel({'admin': False}) - return create_success_response(channel, status=status.HTTP_202_ACCEPTED) - return create_error_response("There is no admin channel configured", - status=status.HTTP_404_NOT_FOUND) - - -class ChannelDetail(APIView): - permission_classes = [IsAuthenticated] - - def get(self, request, guild_id, channel_id, format=None): - try: - guild = Channel.get_channel_by_id(guild_id, channel_id) - except ObjectDoesNotExist: - return create_error_response("Channel Does not Exist", - status=status.HTTP_404_NOT_FOUND) - else: - return create_success_response(guild, - status=status.HTTP_200_OK) - - def put(self, request, guild_id, channel_id, format=None): - channel = Channel.get_channel_by_id(guild_id, channel_id) - - if channel: - data = dict(request.data) - channel = channel.update_channel(data) - return create_success_response(channel, - status=status.HTTP_202_ACCEPTED) - else: - return create_error_response('Channel Does Not Exist', - status=status.HTTP_404_NOT_FOUND) - - def delete(self, request, guild_id, channel_id, format=None): - channel = Channel.get_channel_by_id(guild_id, channel_id) - - if channel: - # data = dict(request.data) - # TODO Add a check to verify user is allowed to delete... - # Possibly in object permissions... - channel.delete() - return create_success_response(guild, - status=status.HTTP_200_OK) - else: - return create_error_response('Channel Does Not Exist', - status=status.HTTP_404_NOT_FOUND) diff --git a/geeksbot_v2/config/__init__.py b/geeksbot_v2/config/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/geeksbot_v2/config/settings/__init__.py b/geeksbot_v2/config/settings/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/geeksbot_v2/config/settings/base.py b/geeksbot_v2/config/settings/base.py deleted file mode 100644 index c03fc31..0000000 --- a/geeksbot_v2/config/settings/base.py +++ /dev/null @@ -1,290 +0,0 @@ -""" -Base settings to build other settings files upon. -""" - -import environ - -ROOT_DIR = ( - environ.Path(__file__) - 3 -) # (geeksbot_v2/config/settings/base.py - 3 = geeksbot_v2/) -APPS_DIR = ROOT_DIR - -env = environ.Env() - -READ_DOT_ENV_FILE = env.bool("DJANGO_READ_DOT_ENV_FILE", default=True) -if READ_DOT_ENV_FILE: - # OS environment variables take precedence over variables from .env - env.read_env(str(ROOT_DIR.path(".env"))) - -# GENERAL -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#debug -DEBUG = env.bool("DJANGO_DEBUG", False) -# Local time zone. Choices are -# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name -# though not all of them may be available with every OS. -# In Windows, this must be set to your system time zone. -TIME_ZONE = "UTC" -# https://docs.djangoproject.com/en/dev/ref/settings/#language-code -LANGUAGE_CODE = "en-us" -# https://docs.djangoproject.com/en/dev/ref/settings/#site-id -SITE_ID = 1 -# https://docs.djangoproject.com/en/dev/ref/settings/#use-i18n -USE_I18N = True -# https://docs.djangoproject.com/en/dev/ref/settings/#use-l10n -USE_L10N = True -# https://docs.djangoproject.com/en/dev/ref/settings/#use-tz -USE_TZ = True -# https://docs.djangoproject.com/en/dev/ref/settings/#locale-paths -LOCALE_PATHS = [ROOT_DIR.path("locale")] - -# DATABASES -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#databases -DATABASES = {"default": env.db("DATABASE_URL")} -DATABASES["default"]["ATOMIC_REQUESTS"] = True -DATABASES['default']['CONN_MAX_AGE'] = 0 - -# URLS -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#root-urlconf -ROOT_URLCONF = "config.urls" -# https://docs.djangoproject.com/en/dev/ref/settings/#wsgi-application -WSGI_APPLICATION = "config.wsgi.application" - -# APPS -# ------------------------------------------------------------------------------ -DJANGO_APPS = [ - "django.contrib.auth", - "django.contrib.contenttypes", - "django.contrib.sessions", - "django.contrib.sites", - "django.contrib.messages", - "django.contrib.staticfiles", - # "django.contrib.humanize", # Handy template tags - "django.contrib.admin", -] -THIRD_PARTY_APPS = [ - "crispy_forms", - "allauth", - "allauth.account", - "allauth.socialaccount", - "allauth.socialaccount.providers.discord", - "rest_framework", - "rest_framework.authtoken", -] - -LOCAL_APPS = [ - "geeksbot_v2.users.apps.UsersConfig", - "geeksbot_v2.guilds.apps.GuildsConfig", - "geeksbot_v2.dmessages.apps.MessagesConfig", - "geeksbot_v2.patreon.apps.PatreonConfig", - "geeksbot_v2.rcon.apps.RconConfig", - "geeksbot_v2.channels.apps.ChannelsConfig", - # Your stuff: custom apps go here -] -# https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps -INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS - -# MIGRATIONS -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#migration-modules -MIGRATION_MODULES = {"sites": "geeksbot_v2.contrib.sites.migrations"} - -# AUTHENTICATION -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#authentication-backends -AUTHENTICATION_BACKENDS = [ - "django.contrib.auth.backends.ModelBackend", - "allauth.account.auth_backends.AuthenticationBackend", -] -# https://docs.djangoproject.com/en/dev/ref/settings/#auth-user-model -AUTH_USER_MODEL = "users.User" -# https://docs.djangoproject.com/en/dev/ref/settings/#login-redirect-url -LOGIN_REDIRECT_URL = "users:redirect" -# https://docs.djangoproject.com/en/dev/ref/settings/#login-url -LOGIN_URL = "account_login" - -# PASSWORDS -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#password-hashers -PASSWORD_HASHERS = [ - # https://docs.djangoproject.com/en/dev/topics/auth/passwords/#using-argon2-with-django - "django.contrib.auth.hashers.Argon2PasswordHasher", - "django.contrib.auth.hashers.PBKDF2PasswordHasher", - "django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher", - "django.contrib.auth.hashers.BCryptSHA256PasswordHasher", -] -# https://docs.djangoproject.com/en/dev/ref/settings/#auth-password-validators -AUTH_PASSWORD_VALIDATORS = [ - { - "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator" - }, - {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"}, - {"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"}, - {"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"}, -] - -# MIDDLEWARE -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#middleware -MIDDLEWARE = [ - "django.middleware.security.SecurityMiddleware", - "django.contrib.sessions.middleware.SessionMiddleware", - "django.middleware.locale.LocaleMiddleware", - "django.middleware.common.CommonMiddleware", - "django.middleware.csrf.CsrfViewMiddleware", - "django.contrib.auth.middleware.AuthenticationMiddleware", - "django.contrib.messages.middleware.MessageMiddleware", - "django.middleware.clickjacking.XFrameOptionsMiddleware", -] - -# STATIC -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#static-root -STATIC_ROOT = str(ROOT_DIR("staticfiles")) -# https://docs.djangoproject.com/en/dev/ref/settings/#static-url -STATIC_URL = "/static/" -# https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS -STATICFILES_DIRS = [str(APPS_DIR.path("static"))] -# https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#staticfiles-finders -STATICFILES_FINDERS = [ - "django.contrib.staticfiles.finders.FileSystemFinder", - "django.contrib.staticfiles.finders.AppDirectoriesFinder", -] - -# MEDIA -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#media-root -MEDIA_ROOT = str(APPS_DIR("media")) -# https://docs.djangoproject.com/en/dev/ref/settings/#media-url -MEDIA_URL = "/media/" - -# TEMPLATES -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#templates -TEMPLATES = [ - { - # https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-TEMPLATES-BACKEND - "BACKEND": "django.template.backends.django.DjangoTemplates", - # https://docs.djangoproject.com/en/dev/ref/settings/#template-dirs - "DIRS": [str(APPS_DIR.path("templates"))], - "OPTIONS": { - # https://docs.djangoproject.com/en/dev/ref/settings/#template-loaders - # https://docs.djangoproject.com/en/dev/ref/templates/api/#loader-types - "loaders": [ - "django.template.loaders.filesystem.Loader", - "django.template.loaders.app_directories.Loader", - ], - # https://docs.djangoproject.com/en/dev/ref/settings/#template-context-processors - "context_processors": [ - "django.template.context_processors.debug", - "django.template.context_processors.request", - "django.contrib.auth.context_processors.auth", - "django.template.context_processors.i18n", - "django.template.context_processors.media", - "django.template.context_processors.static", - "django.template.context_processors.tz", - "django.contrib.messages.context_processors.messages", - ], - }, - } -] -# http://django-crispy-forms.readthedocs.io/en/latest/install.html#template-packs -CRISPY_TEMPLATE_PACK = "bootstrap4" - -# FIXTURES -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#fixture-dirs -FIXTURE_DIRS = (str(APPS_DIR.path("fixtures")),) - -# SECURITY -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#session-cookie-httponly -SESSION_COOKIE_HTTPONLY = True -# https://docs.djangoproject.com/en/dev/ref/settings/#csrf-cookie-httponly -CSRF_COOKIE_HTTPONLY = True -# https://docs.djangoproject.com/en/dev/ref/settings/#secure-browser-xss-filter -SECURE_BROWSER_XSS_FILTER = True -# https://docs.djangoproject.com/en/dev/ref/settings/#x-frame-options -X_FRAME_OPTIONS = "DENY" - -# EMAIL -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#email-backend -EMAIL_BACKEND = env( - "DJANGO_EMAIL_BACKEND", default="django.core.mail.backends.smtp.EmailBackend" -) -# https://docs.djangoproject.com/en/2.2/ref/settings/#email-timeout -EMAIL_TIMEOUT = 5 - -# ADMIN -# ------------------------------------------------------------------------------ -# Django Admin URL. -ADMIN_URL = "admin/" -# https://docs.djangoproject.com/en/dev/ref/settings/#admins -ADMINS = [("""Dustin Pianalto""", "dusty.p@geeksbot.app")] -# https://docs.djangoproject.com/en/dev/ref/settings/#managers -MANAGERS = ADMINS - -# LOGGING -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#logging -# See https://docs.djangoproject.com/en/dev/topics/logging for -# more details on how to customize your logging configuration. -LOGGING = { - "version": 1, - "disable_existing_loggers": False, - "formatters": { - "verbose": { - "format": "%(levelname)s %(asctime)s %(module)s " - "%(process)d %(thread)d %(message)s" - } - }, - "handlers": { - "console": { - "level": "DEBUG", - "class": "logging.StreamHandler", - "formatter": "verbose", - } - }, - "root": {"level": "INFO", "handlers": ["console"]}, -} - -# django-allauth -# ------------------------------------------------------------------------------ -ACCOUNT_ALLOW_REGISTRATION = env.bool("DJANGO_ACCOUNT_ALLOW_REGISTRATION", False) -SOCIAL_ACCOUNT_ALLOW_REGISTRATION = env.bool('DJANGO_SOCIAL_ACCOUNT_ALLOW_REGISTRATION', True) -# https://django-allauth.readthedocs.io/en/latest/configuration.html -ACCOUNT_AUTHENTICATION_METHOD = "username" -# https://django-allauth.readthedocs.io/en/latest/configuration.html -ACCOUNT_EMAIL_REQUIRED = False -# https://django-allauth.readthedocs.io/en/latest/configuration.html -ACCOUNT_EMAIL_VERIFICATION = "optional" -# https://django-allauth.readthedocs.io/en/latest/configuration.html -ACCOUNT_ADAPTER = "geeksbot_v2.users.adapters.AccountAdapter" -# https://django-allauth.readthedocs.io/en/latest/configuration.html -SOCIALACCOUNT_ADAPTER = "geeksbot_v2.users.adapters.SocialAccountAdapter" -ACCOUNT_FORMS = { - 'signup': 'geeksbot_v2.users.forms.UserCreateForm', -} - - -# Your stuff... -# ------------------------------------------------------------------------------ - -REST_FRAMEWORK = { - 'DEFAULT_AUTHENTICATION_CLASSES': [ - 'rest_framework.authentication.TokenAuthentication', - ], - "DEFAULT_RENDERER_CLASSES": [ - "rest_framework.renderers.JSONRenderer", - ], - "DEFAULT_PARSER_CLASSES": [ - 'rest_framework.parsers.JSONParser', - ], - "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.LimitOffsetPagination", - "PAGE_SIZE": 100, -} - -SILENCED_SYSTEM_CHECKS = ["auth.W004"] diff --git a/geeksbot_v2/config/settings/local.py b/geeksbot_v2/config/settings/local.py deleted file mode 100644 index 15c3aa5..0000000 --- a/geeksbot_v2/config/settings/local.py +++ /dev/null @@ -1,62 +0,0 @@ -from .base import * # noqa -from .base import env - -# GENERAL -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#debug -DEBUG = True -# https://docs.djangoproject.com/en/dev/ref/settings/#secret-key -SECRET_KEY = env( - "DJANGO_SECRET_KEY", - default="j67xnBm5ZQ7SAQwhvaMnD4WAW1EeEFVQx0KxBOyHRMYCR4LV0rVkuslZJs1rtPUE", -) -# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts -ALLOWED_HOSTS = ["localhost", "0.0.0.0", "127.0.0.1"] - -# CACHES -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#caches -CACHES = { - "default": { - "BACKEND": "django.core.cache.backends.locmem.LocMemCache", - "LOCATION": "", - } -} - -# EMAIL -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#email-backend -EMAIL_BACKEND = env( - "DJANGO_EMAIL_BACKEND", default="django.core.mail.backends.console.EmailBackend" -) -# https://docs.djangoproject.com/en/dev/ref/settings/#email-host -EMAIL_HOST = "localhost" -# https://docs.djangoproject.com/en/dev/ref/settings/#email-port -EMAIL_PORT = 1025 - -# django-debug-toolbar -# ------------------------------------------------------------------------------ -# https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#prerequisites -INSTALLED_APPS += ["debug_toolbar"] # noqa F405 -# https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#middleware -MIDDLEWARE += ["debug_toolbar.middleware.DebugToolbarMiddleware"] # noqa F405 -# https://django-debug-toolbar.readthedocs.io/en/latest/configuration.html#debug-toolbar-config -DEBUG_TOOLBAR_CONFIG = { - "DISABLE_PANELS": ["debug_toolbar.panels.redirects.RedirectsPanel"], - "SHOW_TEMPLATE_CONTEXT": True, -} -# https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#internal-ips -INTERNAL_IPS = ["127.0.0.1", "10.0.2.2"] -if env("USE_DOCKER") == "yes": - import socket - - hostname, _, ips = socket.gethostbyname_ex(socket.gethostname()) - INTERNAL_IPS += [ip[:-1] + "1" for ip in ips] - -# django-extensions -# ------------------------------------------------------------------------------ -# https://django-extensions.readthedocs.io/en/latest/installation_instructions.html#configuration -INSTALLED_APPS += ["django_extensions"] # noqa F405 - -# Your stuff... -# ------------------------------------------------------------------------------ diff --git a/geeksbot_v2/config/settings/production.py b/geeksbot_v2/config/settings/production.py deleted file mode 100644 index e503623..0000000 --- a/geeksbot_v2/config/settings/production.py +++ /dev/null @@ -1,155 +0,0 @@ -from .base import * # noqa -from .base import env - -# GENERAL -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#secret-key -SECRET_KEY = env("DJANGO_SECRET_KEY") -# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts -ALLOWED_HOSTS = env.list("DJANGO_ALLOWED_HOSTS", default=["geeksbot.app"]) - -# DATABASES -# ------------------------------------------------------------------------------ -DATABASES["default"] = env.db("DATABASE_URL") # noqa F405 -DATABASES["default"]["ATOMIC_REQUESTS"] = True # noqa F405 -DATABASES["default"]["CONN_MAX_AGE"] = env.int("CONN_MAX_AGE", default=60) # noqa F405 - -# CACHES -# ------------------------------------------------------------------------------ -CACHES = { - "default": { - "BACKEND": "django_redis.cache.RedisCache", - "LOCATION": env("REDIS_URL"), - "OPTIONS": { - "CLIENT_CLASS": "django_redis.client.DefaultClient", - # Mimicing memcache behavior. - # http://niwinz.github.io/django-redis/latest/#_memcached_exceptions_behavior - "IGNORE_EXCEPTIONS": True, - }, - } -} - -# SECURITY -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#secure-proxy-ssl-header -SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") -# https://docs.djangoproject.com/en/dev/ref/settings/#secure-ssl-redirect -SECURE_SSL_REDIRECT = env.bool("DJANGO_SECURE_SSL_REDIRECT", default=True) -# https://docs.djangoproject.com/en/dev/ref/settings/#session-cookie-secure -SESSION_COOKIE_SECURE = True -# https://docs.djangoproject.com/en/dev/ref/settings/#csrf-cookie-secure -CSRF_COOKIE_SECURE = True -# https://docs.djangoproject.com/en/dev/topics/security/#ssl-https -# https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-seconds -# TODO: set this to 60 seconds first and then to 518400 once you prove the former works -SECURE_HSTS_SECONDS = 60 -# https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-include-subdomains -SECURE_HSTS_INCLUDE_SUBDOMAINS = env.bool( - "DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS", default=True -) -# https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-preload -SECURE_HSTS_PRELOAD = env.bool("DJANGO_SECURE_HSTS_PRELOAD", default=True) -# https://docs.djangoproject.com/en/dev/ref/middleware/#x-content-type-options-nosniff -SECURE_CONTENT_TYPE_NOSNIFF = env.bool( - "DJANGO_SECURE_CONTENT_TYPE_NOSNIFF", default=True -) - -# MEDIA -# ------------------------------------------------------------------------------ - -# TEMPLATES -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#templates -TEMPLATES[0]["OPTIONS"]["loaders"] = [ # noqa F405 - ( - "django.template.loaders.cached.Loader", - [ - "django.template.loaders.filesystem.Loader", - "django.template.loaders.app_directories.Loader", - ], - ) -] - -# EMAIL -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#default-from-email -DEFAULT_FROM_EMAIL = env( - "DJANGO_DEFAULT_FROM_EMAIL", default="geeksbot " -) -# https://docs.djangoproject.com/en/dev/ref/settings/#server-email -SERVER_EMAIL = env("DJANGO_SERVER_EMAIL", default=DEFAULT_FROM_EMAIL) -# https://docs.djangoproject.com/en/dev/ref/settings/#email-subject-prefix -EMAIL_SUBJECT_PREFIX = env( - "DJANGO_EMAIL_SUBJECT_PREFIX", default="[geeksbot]" -) - -# ADMIN -# ------------------------------------------------------------------------------ -# Django Admin URL regex. -ADMIN_URL = env("DJANGO_ADMIN_URL") - -# Anymail (Mailgun) -# ------------------------------------------------------------------------------ -# https://anymail.readthedocs.io/en/stable/installation/#installing-anymail -INSTALLED_APPS += ["anymail"] # noqa F405 -EMAIL_BACKEND = "anymail.backends.mailgun.EmailBackend" -# https://anymail.readthedocs.io/en/stable/installation/#anymail-settings-reference -ANYMAIL = { - "MAILGUN_API_KEY": env("MAILGUN_API_KEY"), - "MAILGUN_SENDER_DOMAIN": env("MAILGUN_DOMAIN"), - "MAILGUN_API_URL": env("MAILGUN_API_URL", default="https://api.mailgun.net/v3"), -} - -# Collectfast -# ------------------------------------------------------------------------------ -# https://github.com/antonagestam/collectfast#installation -INSTALLED_APPS = ["collectfast"] + INSTALLED_APPS # noqa F405 -AWS_PRELOAD_METADATA = True - -# LOGGING -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#logging -# See https://docs.djangoproject.com/en/dev/topics/logging for -# more details on how to customize your logging configuration. -# A sample logging configuration. The only tangible logging -# performed by this configuration is to send an email to -# the site admins on every HTTP 500 error when DEBUG=False. -LOGGING = { - "version": 1, - "disable_existing_loggers": False, - "filters": {"require_debug_false": {"()": "django.utils.log.RequireDebugFalse"}}, - "formatters": { - "verbose": { - "format": "%(levelname)s %(asctime)s %(module)s " - "%(process)d %(thread)d %(message)s" - } - }, - "handlers": { - "mail_admins": { - "level": "ERROR", - "filters": ["require_debug_false"], - "class": "django.utils.log.AdminEmailHandler", - }, - "console": { - "level": "DEBUG", - "class": "logging.StreamHandler", - "formatter": "verbose", - }, - }, - "root": {"level": "INFO", "handlers": ["console"]}, - "loggers": { - "django.request": { - "handlers": ["mail_admins"], - "level": "ERROR", - "propagate": True, - }, - "django.security.DisallowedHost": { - "level": "ERROR", - "handlers": ["console", "mail_admins"], - "propagate": True, - }, - }, -} - -# Your stuff... -# ------------------------------------------------------------------------------ diff --git a/geeksbot_v2/config/settings/test.py b/geeksbot_v2/config/settings/test.py deleted file mode 100644 index 3a4c593..0000000 --- a/geeksbot_v2/config/settings/test.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -With these settings, tests run faster. -""" - -from .base import * # noqa -from .base import env - -# GENERAL -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#debug -DEBUG = False -# https://docs.djangoproject.com/en/dev/ref/settings/#secret-key -SECRET_KEY = env( - "DJANGO_SECRET_KEY", - default="f2z33VJdMTuS8AHpyHr1p2AAR9daYVQFMLEqBGxEP2aZLmtBpRVudyOrhK1DL9Ov", -) -# https://docs.djangoproject.com/en/dev/ref/settings/#test-runner -TEST_RUNNER = "django.test.runner.DiscoverRunner" - -# CACHES -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#caches -CACHES = { - "default": { - "BACKEND": "django.core.cache.backends.locmem.LocMemCache", - "LOCATION": "", - } -} - -# PASSWORDS -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#password-hashers -PASSWORD_HASHERS = ["django.contrib.auth.hashers.MD5PasswordHasher"] - -# TEMPLATES -# ------------------------------------------------------------------------------ -TEMPLATES[0]["OPTIONS"]["loaders"] = [ # noqa F405 - ( - "django.template.loaders.cached.Loader", - [ - "django.template.loaders.filesystem.Loader", - "django.template.loaders.app_directories.Loader", - ], - ) -] - -# EMAIL -# ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#email-backend -EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend" - -# Your stuff... -# ------------------------------------------------------------------------------ diff --git a/geeksbot_v2/config/urls.py b/geeksbot_v2/config/urls.py deleted file mode 100644 index 80663f0..0000000 --- a/geeksbot_v2/config/urls.py +++ /dev/null @@ -1,50 +0,0 @@ -from django.conf import settings -from django.urls import include, path -from django.conf.urls.static import static -from django.contrib import admin -from django.views.generic import TemplateView -from django.views import defaults as default_views - -urlpatterns = [ - path("", TemplateView.as_view(template_name="pages/home.html"), name="home"), - path( - "about/", TemplateView.as_view(template_name="pages/about.html"), name="about" - ), - # Django Admin, use {% url 'admin:index' %} - path(settings.ADMIN_URL, admin.site.urls), - # User management - path("users/", include("geeksbot_v2.users.urls", namespace="users")), - path("accounts/", include("allauth.urls")), - # Your stuff: custom urls includes go here - path("api/users/", include("geeksbot_v2.users.api_urls", namespace="users_api")), - path("api/guilds/", include("geeksbot_v2.guilds.api_urls", namespace="guilds_api")), - path("api/channels/", include("geeksbot_v2.channels.api_urls", namespace="channels_api")), - path("api/messages/", include("geeksbot_v2.dmessages.api_urls", namespace="messages_api")), - path("api/rcon/", include("geeksbot_v2.rcon.api_urls", namespace="rcon_api")), -] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) - -if settings.DEBUG: - # This allows the error pages to be debugged during development, just visit - # these url in browser to see how these error pages look like. - urlpatterns += [ - path( - "400/", - default_views.bad_request, - kwargs={"exception": Exception("Bad Request!")}, - ), - path( - "403/", - default_views.permission_denied, - kwargs={"exception": Exception("Permission Denied")}, - ), - path( - "404/", - default_views.page_not_found, - kwargs={"exception": Exception("Page not Found")}, - ), - path("500/", default_views.server_error), - ] - if "debug_toolbar" in settings.INSTALLED_APPS: - import debug_toolbar - - urlpatterns = [path("__debug__/", include(debug_toolbar.urls))] + urlpatterns diff --git a/geeksbot_v2/config/wsgi.py b/geeksbot_v2/config/wsgi.py deleted file mode 100644 index ebac06a..0000000 --- a/geeksbot_v2/config/wsgi.py +++ /dev/null @@ -1,39 +0,0 @@ -""" -WSGI config for geeksbot project. - -This module contains the WSGI application used by Django's development server -and any production WSGI deployments. It should expose a module-level variable -named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover -this application via the ``WSGI_APPLICATION`` setting. - -Usually you will have the standard Django WSGI application here, but it also -might make sense to replace the whole Django WSGI application with a custom one -that later delegates to the Django one. For example, you could introduce WSGI -middleware here, or combine a Django application with an application of another -framework. - -""" -import os -import sys - -from django.core.wsgi import get_wsgi_application - -# This allows easy placement of apps within the interior -# geeksbot_v2 directory. -app_path = os.path.abspath( - os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir) -) -sys.path.append(os.path.join(app_path, "geeksbot_v2")) -# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks -# if running multiple sites in the same mod_wsgi process. To fix this, use -# mod_wsgi daemon mode with each site in its own daemon process, or use -# os.environ["DJANGO_SETTINGS_MODULE"] = "config.settings.production" -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production") - -# This application object is used by any WSGI server configured to use this -# file. This includes Django's development server, if the WSGI_APPLICATION -# setting points here. -application = get_wsgi_application() -# Apply WSGI middleware here. -# from helloworld.wsgi import HelloWorldApplication -# application = HelloWorldApplication(application) diff --git a/geeksbot_v2/conftest.py b/geeksbot_v2/conftest.py deleted file mode 100644 index 6336add..0000000 --- a/geeksbot_v2/conftest.py +++ /dev/null @@ -1,20 +0,0 @@ -import pytest -from django.conf import settings -from django.test import RequestFactory - -from geeksbot_v2.users.tests.factories import UserFactory - - -@pytest.fixture(autouse=True) -def media_storage(settings, tmpdir): - settings.MEDIA_ROOT = tmpdir.strpath - - -@pytest.fixture -def user() -> settings.AUTH_USER_MODEL: - return UserFactory() - - -@pytest.fixture -def request_factory() -> RequestFactory: - return RequestFactory() diff --git a/geeksbot_v2/contrib/__init__.py b/geeksbot_v2/contrib/__init__.py deleted file mode 100644 index 1c7ecc8..0000000 --- a/geeksbot_v2/contrib/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -""" -To understand why this file is here, please read: - -http://cookiecutter-django.readthedocs.io/en/latest/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django -""" diff --git a/geeksbot_v2/contrib/sites/__init__.py b/geeksbot_v2/contrib/sites/__init__.py deleted file mode 100644 index 1c7ecc8..0000000 --- a/geeksbot_v2/contrib/sites/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -""" -To understand why this file is here, please read: - -http://cookiecutter-django.readthedocs.io/en/latest/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django -""" diff --git a/geeksbot_v2/contrib/sites/migrations/0001_initial.py b/geeksbot_v2/contrib/sites/migrations/0001_initial.py deleted file mode 100644 index c0c8906..0000000 --- a/geeksbot_v2/contrib/sites/migrations/0001_initial.py +++ /dev/null @@ -1,42 +0,0 @@ -import django.contrib.sites.models -from django.contrib.sites.models import _simple_domain_name_validator -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [] - - operations = [ - migrations.CreateModel( - name="Site", - fields=[ - ( - "id", - models.AutoField( - verbose_name="ID", - serialize=False, - auto_created=True, - primary_key=True, - ), - ), - ( - "domain", - models.CharField( - max_length=100, - verbose_name="domain name", - validators=[_simple_domain_name_validator], - ), - ), - ("name", models.CharField(max_length=50, verbose_name="display name")), - ], - options={ - "ordering": ("domain",), - "db_table": "django_site", - "verbose_name": "site", - "verbose_name_plural": "sites", - }, - bases=(models.Model,), - managers=[("objects", django.contrib.sites.models.SiteManager())], - ) - ] \ No newline at end of file diff --git a/geeksbot_v2/contrib/sites/migrations/0002_alter_domain_unique.py b/geeksbot_v2/contrib/sites/migrations/0002_alter_domain_unique.py deleted file mode 100644 index 2fcbc4e..0000000 --- a/geeksbot_v2/contrib/sites/migrations/0002_alter_domain_unique.py +++ /dev/null @@ -1,20 +0,0 @@ -import django.contrib.sites.models -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [("sites", "0001_initial")] - - operations = [ - migrations.AlterField( - model_name="site", - name="domain", - field=models.CharField( - max_length=100, - unique=True, - validators=[django.contrib.sites.models._simple_domain_name_validator], - verbose_name="domain name", - ), - ) - ] \ No newline at end of file diff --git a/geeksbot_v2/contrib/sites/migrations/0003_set_site_domain_and_name.py b/geeksbot_v2/contrib/sites/migrations/0003_set_site_domain_and_name.py deleted file mode 100644 index 93aab61..0000000 --- a/geeksbot_v2/contrib/sites/migrations/0003_set_site_domain_and_name.py +++ /dev/null @@ -1,33 +0,0 @@ -""" -To understand why this file is here, please read: -http://cookiecutter-django.readthedocs.io/en/latest/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django -""" -from django.conf import settings -from django.db import migrations - - -def update_site_forward(apps, schema_editor): - """Set site domain and name.""" - Site = apps.get_model("sites", "Site") - Site.objects.update_or_create( - id=settings.SITE_ID, - defaults={ - "domain": "geeksbot.app", - "name": "geeksbot", - }, - ) - - -def update_site_backward(apps, schema_editor): - """Revert site domain and name to default.""" - Site = apps.get_model("sites", "Site") - Site.objects.update_or_create( - id=settings.SITE_ID, defaults={"domain": "example.com", "name": "example.com"} - ) - - -class Migration(migrations.Migration): - - dependencies = [("sites", "0002_alter_domain_unique")] - - operations = [migrations.RunPython(update_site_forward, update_site_backward)] \ No newline at end of file diff --git a/geeksbot_v2/contrib/sites/migrations/__init__.py b/geeksbot_v2/contrib/sites/migrations/__init__.py deleted file mode 100644 index 1c7ecc8..0000000 --- a/geeksbot_v2/contrib/sites/migrations/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -""" -To understand why this file is here, please read: - -http://cookiecutter-django.readthedocs.io/en/latest/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django -""" diff --git a/geeksbot_v2/dmessages/__init__.py b/geeksbot_v2/dmessages/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/geeksbot_v2/dmessages/admin.py b/geeksbot_v2/dmessages/admin.py deleted file mode 100644 index e14fb8b..0000000 --- a/geeksbot_v2/dmessages/admin.py +++ /dev/null @@ -1,10 +0,0 @@ -from django.contrib import admin - -from .models import Message -from .models import GuildInfo -from .models import AdminRequest - -# Register your models here. -admin.site.register(Message) -admin.site.register(GuildInfo) -admin.site.register(AdminRequest) \ No newline at end of file diff --git a/geeksbot_v2/dmessages/api_urls.py b/geeksbot_v2/dmessages/api_urls.py deleted file mode 100644 index 5891225..0000000 --- a/geeksbot_v2/dmessages/api_urls.py +++ /dev/null @@ -1,21 +0,0 @@ -from django.urls import path - -from .views import MessageDetailAPI, MessagesAPI -from .views import RequestDetailAPI, RequestsAPI -from .views import CommentDetailAPI, CommentsAPI, CommentsCountAPI -from .views import WaitForMessageAPI -from .views import UserRequestsAPI - -app_name = "messages_api" -urlpatterns = [ - path("", view=MessagesAPI.as_view(), name="message_list"), - path("/", view=MessageDetailAPI.as_view(), name='message_detail'), - path("/requests/", view=RequestsAPI.as_view(), name="requests_list"), - path("/requests//", view=RequestDetailAPI.as_view(), name='request_detail'), - path("/requests//comments/", view=CommentsAPI.as_view(), name="comments_list"), - path("/requests//comments/count/", view=CommentsCountAPI.as_view(), name="comments_count"), - path("/requests//comments//", view=CommentDetailAPI.as_view(), name='comment_detail'), - path("/requests/user//", view=UserRequestsAPI.as_view(), name='user_requests_list'), - path("/wait/", view=WaitForMessageAPI.as_view(), name='wait_for_message'), - path("/wait//", view=WaitForMessageAPI.as_view(), name='wait_for_message_timeout'), -] diff --git a/geeksbot_v2/dmessages/apps.py b/geeksbot_v2/dmessages/apps.py deleted file mode 100644 index 1355c6c..0000000 --- a/geeksbot_v2/dmessages/apps.py +++ /dev/null @@ -1,7 +0,0 @@ -from django.apps import AppConfig -from django.utils.translation import gettext_lazy as _ - - -class MessagesConfig(AppConfig): - name = 'geeksbot_v2.dmessages' - verbose_name = _("DMessages") diff --git a/geeksbot_v2/dmessages/migrations/0001_initial.py b/geeksbot_v2/dmessages/migrations/0001_initial.py deleted file mode 100644 index bdb189d..0000000 --- a/geeksbot_v2/dmessages/migrations/0001_initial.py +++ /dev/null @@ -1,59 +0,0 @@ -# Generated by Django 2.2.4 on 2019-09-20 21:39 - -import django.contrib.postgres.fields -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ] - - operations = [ - migrations.CreateModel( - name='AdminComment', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('content', models.CharField(max_length=1000)), - ('updated_at', models.DateTimeField(auto_now_add=True)), - ], - ), - migrations.CreateModel( - name='AdminRequest', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('completed', models.BooleanField(default=False)), - ('requested_at', models.DateTimeField(auto_now_add=True)), - ('completed_at', models.DateTimeField(blank=True, default=None, null=True)), - ('completed_message', models.CharField(blank=True, default=None, max_length=1000, null=True)), - ('content', models.CharField(max_length=2000)), - ], - ), - migrations.CreateModel( - name='GuildInfo', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('type', models.PositiveSmallIntegerField()), - ('text', models.TextField(max_length=1980)), - ('format', models.PositiveSmallIntegerField()), - ('channel', models.CharField(max_length=30)), - ('message_number', models.PositiveSmallIntegerField()), - ], - ), - migrations.CreateModel( - name='Message', - fields=[ - ('id', models.CharField(max_length=30, primary_key=True, serialize=False)), - ('created_at', models.DateTimeField()), - ('modified_at', models.DateTimeField(blank=True, null=True)), - ('deleted_at', models.DateTimeField(blank=True, null=True)), - ('content', models.CharField(max_length=2000)), - ('previous_content', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=2000), default=list, size=None)), - ('tagged_everyone', models.BooleanField()), - ('embeds', django.contrib.postgres.fields.ArrayField(base_field=models.TextField(), default=list, size=None)), - ('previous_embeds', django.contrib.postgres.fields.ArrayField(base_field=django.contrib.postgres.fields.ArrayField(base_field=models.TextField(), size=None), default=list, size=None)), - ], - ), - ] diff --git a/geeksbot_v2/dmessages/migrations/0002_auto_20190920_2139.py b/geeksbot_v2/dmessages/migrations/0002_auto_20190920_2139.py deleted file mode 100644 index 4258381..0000000 --- a/geeksbot_v2/dmessages/migrations/0002_auto_20190920_2139.py +++ /dev/null @@ -1,95 +0,0 @@ -# Generated by Django 2.2.4 on 2019-09-20 21:39 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('guilds', '0001_initial'), - ('dmessages', '0001_initial'), - ('channels', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='message', - name='author', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to=settings.AUTH_USER_MODEL), - ), - migrations.AddField( - model_name='message', - name='channel', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='channels.Channel'), - ), - migrations.AddField( - model_name='message', - name='guild', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='guilds.Guild'), - ), - migrations.AddField( - model_name='message', - name='tagged_channels', - field=models.ManyToManyField(related_name='_message_tagged_channels_+', to='channels.Channel'), - ), - migrations.AddField( - model_name='message', - name='tagged_roles', - field=models.ManyToManyField(to='guilds.Role'), - ), - migrations.AddField( - model_name='message', - name='tagged_users', - field=models.ManyToManyField(related_name='_message_tagged_users_+', to=settings.AUTH_USER_MODEL), - ), - migrations.AddField( - model_name='guildinfo', - name='guild', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='guilds.Guild'), - ), - migrations.AddField( - model_name='guildinfo', - name='message', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dmessages.Message'), - ), - migrations.AddField( - model_name='adminrequest', - name='author', - field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL), - ), - migrations.AddField( - model_name='adminrequest', - name='channel', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='channels.Channel'), - ), - migrations.AddField( - model_name='adminrequest', - name='completed_by', - field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL), - ), - migrations.AddField( - model_name='adminrequest', - name='guild', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='guilds.Guild'), - ), - migrations.AddField( - model_name='adminrequest', - name='message', - field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='dmessages.Message'), - ), - migrations.AddField( - model_name='admincomment', - name='author', - field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to=settings.AUTH_USER_MODEL), - ), - migrations.AddField( - model_name='admincomment', - name='request', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='dmessages.AdminRequest'), - ), - ] diff --git a/geeksbot_v2/dmessages/migrations/0003_auto_20190921_0721.py b/geeksbot_v2/dmessages/migrations/0003_auto_20190921_0721.py deleted file mode 100644 index 5f3b8f3..0000000 --- a/geeksbot_v2/dmessages/migrations/0003_auto_20190921_0721.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.2.4 on 2019-09-21 07:21 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('dmessages', '0002_auto_20190920_2139'), - ] - - operations = [ - migrations.AlterField( - model_name='message', - name='content', - field=models.CharField(blank=True, max_length=2000, null=True), - ), - ] diff --git a/geeksbot_v2/dmessages/migrations/__init__.py b/geeksbot_v2/dmessages/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/geeksbot_v2/dmessages/models.py b/geeksbot_v2/dmessages/models.py deleted file mode 100644 index e2ed99c..0000000 --- a/geeksbot_v2/dmessages/models.py +++ /dev/null @@ -1,291 +0,0 @@ -from datetime import datetime - -from django.db import models -from django.core.exceptions import ObjectDoesNotExist -from django.contrib.postgres.fields import ArrayField -from rest_framework import status - -from geeksbot_v2.guilds.models import Guild -from geeksbot_v2.guilds.models import Role -from geeksbot_v2.users.models import User -from geeksbot_v2.channels.models import Channel -from .utils import create_error_response -from .utils import create_success_response -from .utils import create_request_success_response -from .utils import create_comment_success_response - -# Create your models here. - - -class Message(models.Model): - id = models.CharField(max_length=30, primary_key=True) - author = models.ForeignKey(User, related_name="+", on_delete=models.CASCADE) - guild = models.ForeignKey(Guild, on_delete=models.CASCADE) - channel = models.ForeignKey(Channel, related_name="+", on_delete=models.CASCADE) - created_at = models.DateTimeField() - modified_at = models.DateTimeField(null=True, blank=True) - deleted_at = models.DateTimeField(null=True, blank=True) - content = models.CharField(max_length=2000, null=True, blank=True) - previous_content = ArrayField(models.CharField(max_length=2000), default=list) - tagged_users = models.ManyToManyField(User, related_name="+") - tagged_channels = models.ManyToManyField(Channel, related_name="+") - tagged_roles = models.ManyToManyField(Role) - tagged_everyone = models.BooleanField() - embeds = ArrayField(models.TextField(), default=list) - previous_embeds = ArrayField(ArrayField(models.TextField()), default=list) - - @classmethod - def add_new_message(cls, data): - id = data.get('id') - if id and cls.get_message_by_id(id): - return create_error_response("Message Already Exists", - status=status.HTTP_409_CONFLICT) - author_id = data.get('author') - guild_id = data.get('guild') - channel_id = data.get('channel') - created_at = data.get('created_at') - content = data.get('content') - tagged_everyone = data.get('tagged_everyone') - if not (id and author_id and guild_id and channel_id and created_at and (tagged_everyone is not None)): - return create_error_response("One or more required fields are missing.", - status=status.HTTP_400_BAD_REQUEST) - author = User.get_user_by_id(author_id) - if not isinstance(author, User): - return create_error_response("Author Does Not Exist", - status=status.HTTP_404_NOT_FOUND) - guild = Guild.get_guild_by_id(guild_id) - if not isinstance(guild, Guild): - return create_error_response("Guild Does Not Exist", - status=status.HTTP_404_NOT_FOUND) - channel = Channel.get_channel_by_id(guild_id, channel_id) - if not isinstance(channel, Channel): - return create_error_response("Channel Does Not Exist", - status=status.HTTP_404_NOT_FOUND) - created_at = datetime.fromtimestamp(created_at) - - message = cls( - id=id, - author=author, - guild=guild, - channel=channel, - created_at=created_at, - tagged_everyone=tagged_everyone or False, - content=content or '', - embeds=data.get('embeds') or [] - ) - message.save() - if data.get('tagged_users'): - tagged_users = data.get('tagged_users') - for user_id in tagged_users: - user = User.get_user_by_id(user_id) - if user: - message.tagged_users.add(user) - if data.get('tagged_roles'): - tagged_roles = data.get('tagged_roles') - for role_id in tagged_roles: - role = Role.get_role_by_id(role_id) - if role: - message.tagged_roles.add(role) - if data.get('tagged_channels'): - tagged_channels = data.get('tagged_channels') - for channel_id in tagged_channels: - channel = Channel.get_channel_by_id(guild_id, channel_id) - if channel: - message.tagged_channels.add(channel) - - return create_success_response(message, status.HTTP_201_CREATED, many=False) - - def update_message(self, data): - if data.get('modified_at'): - self.modified_at = datetime.fromtimestamp(int(data.get('modified_at'))) - if data.get('deleted_at'): - self.deleted_at = datetime.fromtimestamp(int(data.get('deleted_at'))) - if data.get('content'): - content = data.get('content') - if content != self.content: - self.previous_content.append(self.content) - self.content = content - if data.get('embeds'): - embeds = data.get('embeds') - if embeds != self.embeds: - self.previous_embeds.append(self.embeds) - self.embeds = embeds - if data.get('tagged_everyone'): - tagged_everyone = data.get('tagged_everyone') - if self.tagged_everyone or tagged_everyone: - self.tagged_everyone = True - if data.get('tagged_users'): - tagged_users = data.get('tagged_users') - for user in tagged_users: - if user not in self.tagged_users: - self.tagged_users.append(user) - if data.get('tagged_roles'): - tagged_roles = data.get('tagged_roles') - for role in tagged_roles: - if role not in self.tagged_roles: - self.tagged_roles.append(role) - if data.get('tagged_channels'): - tagged_channels = data.get('tagged_channels') - for channel in tagged_channels: - if channel not in self.tagged_channels: - self.tagged_channels.append(channel) - - self.save() - return create_success_response(self, status.HTTP_202_ACCEPTED, many=False) - - @classmethod - def get_message_by_id(cls, id): - try: - return cls.objects.get(id=id) - except ObjectDoesNotExist: - return None - - def __str__(self): - return (f'{self.created_at} | ' - f'{self.author.id}' - f'{" | Modified" if self.modified_at else ""}' - f'{" | Deleted" if self.deleted_at else ""}') - - -class GuildInfo(models.Model): - message = models.ForeignKey( - Message, on_delete=models.CASCADE, blank=True, null=True - ) - guild = models.ForeignKey(Guild, on_delete=models.CASCADE) - type = models.PositiveSmallIntegerField() - text = models.TextField(max_length=1980) - format = models.PositiveSmallIntegerField() - channel = models.CharField(max_length=30) - message_number = models.PositiveSmallIntegerField() - - def __str__(self): - return f"{self.guild.id} | {self.text[:25]}" - - -class AdminRequest(models.Model): - guild = models.ForeignKey(Guild, on_delete=models.CASCADE) - author = models.ForeignKey(User, related_name="+", on_delete=models.DO_NOTHING) - message = models.ForeignKey(Message, on_delete=models.DO_NOTHING) - channel = models.ForeignKey(Channel, on_delete=models.DO_NOTHING, null=True) - completed = models.BooleanField(default=False) - requested_at = models.DateTimeField(auto_now_add=True, blank=True) - completed_at = models.DateTimeField(null=True, blank=True, default=None) - completed_by = models.ForeignKey( - User, related_name="+", on_delete=models.DO_NOTHING, null=True, blank=True, default=None - ) - completed_message = models.CharField(max_length=1000, null=True, blank=True, default=None) - content = models.CharField(max_length=2000) - - def update_request(self, data): - completed = data.get('completed', False) - completed_by_id = data.get('completed_by') - completed_message = data.get('message', '') - if not self.completed and completed: - self.completed = completed - self.completed_at = datetime.utcnow() - self.completed_message = completed_message - user = User.get_user_by_id(completed_by_id) - if not isinstance(user, User): - return create_error_response('User Does Not Exist', - status=status.HTTP_404_NOT_FOUND) - self.completed_by = user - self.save() - return create_request_success_response(self, status.HTTP_202_ACCEPTED) - - @classmethod - def add_new_request(cls, guild_id, data): - author_id = data.get('author') - message_id = data.get('message') - channel_id = data.get('channel') - content = data.get('content') - if not (guild_id and author_id and message_id and channel_id and content): - return create_error_response("One or more of the required fields are missing.", - status=status.HTTP_400_BAD_REQUEST) - guild = Guild.get_guild_by_id(guild_id) - if not isinstance(guild, Guild): - return create_error_response('Guild Does Not Exist', - status=status.HTTP_404_NOT_FOUND) - author = User.get_user_by_id(author_id) - if not isinstance(author, User): - return create_error_response('Author Does Not Exist', - status=status.HTTP_404_NOT_FOUND) - message = Message.get_message_by_id(message_id) - if not isinstance(message, Message): - return create_error_response('Message Does Not Exist', - status=status.HTTP_404_NOT_FOUND) - channel = Channel.get_channel_by_id(guild_id, channel_id) - if not isinstance(channel, Channel): - return create_error_response('Channel Does Not Exist', - status=status.HTTP_404_NOT_FOUND) - - print('test') - - request = cls( - guild=guild, - author=author, - message=message, - channel=channel, - content=content - ) - request.save() - return create_request_success_response(request, status.HTTP_201_CREATED, many=False) - - @classmethod - def get_open_requests_by_guild(cls, guild_id): - return cls.objects.filter(guild__id=guild_id).filter(completed=False) - - @classmethod - def get_open_request_by_id(cls, guild_id, request_id): - try: - return cls.get_open_requests_by_guild(guild_id).get(id=request_id) - except ObjectDoesNotExist: - return None - - def __str__(self): - return f"{self.guild.id} | {self.requested_at} | By {self.author.id}" - - @classmethod - def get_open_requests_by_guild_author(cls, guild_id, author_id): - return cls.get_open_requests_by_guild(guild_id).filter(author__id=author_id) - - -class AdminComment(models.Model): - request = models.ForeignKey(AdminRequest, on_delete=models.CASCADE) - author = models.ForeignKey(User, on_delete=models.DO_NOTHING) - content = models.CharField(max_length=1000) - updated_at = models.DateTimeField(auto_now_add=True, blank=True) - - @classmethod - def add_new_comment(cls, data, guild_id, request_id): - author_id = data.get('author') - content = data.get('content') - if not (request_id and author_id and content): - return create_error_response('Request, Author, and Content are required fields', - status=status.HTTP_400_BAD_REQUEST) - request = AdminRequest.get_open_request_by_id(guild_id, request_id) - if not isinstance(request, AdminRequest): - return create_error_response("Admin Request Does Not Exist", - status=status.HTTP_404_NOT_FOUND) - author = User.get_user_by_id(author_id) - if not isinstance(author, User): - return create_error_response("Author Does Not Exist", - status=status.HTTP_404_NOT_FOUND) - - comment = cls( - request=request, - author=author, - content=content - ) - comment.save() - return create_comment_success_response(comment, status.HTTP_201_CREATED, many=False) - - @classmethod - def get_comment_by_id(cls, comment_id): - try: - return cls.objects.get(id=comment_id) - except ObjectDoesNotExist: - return None - - @classmethod - def get_comments_by_request(cls, request): - return cls.objects.filter(request=request).order_by('updated_at') diff --git a/geeksbot_v2/dmessages/serializers.py b/geeksbot_v2/dmessages/serializers.py deleted file mode 100644 index 082cb25..0000000 --- a/geeksbot_v2/dmessages/serializers.py +++ /dev/null @@ -1,30 +0,0 @@ -from rest_framework import serializers - -from .models import Message -from .models import GuildInfo -from .models import AdminRequest -from .models import AdminComment - - -class MessageSerializer(serializers.ModelSerializer): - class Meta: - model = Message - fields = "__all__" - - -class GuildInfoSerializer(serializers.ModelSerializer): - class Meta: - model = GuildInfo - fields = "__all__" - - -class AdminRequestSerializer(serializers.ModelSerializer): - class Meta: - model = AdminRequest - fields = "__all__" - - -class AdminCommentSerializer(serializers.ModelSerializer): - class Meta: - model = AdminComment - fields = "__all__" diff --git a/geeksbot_v2/dmessages/tests.py b/geeksbot_v2/dmessages/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/geeksbot_v2/dmessages/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/geeksbot_v2/dmessages/utils.py b/geeksbot_v2/dmessages/utils.py deleted file mode 100644 index ab5c646..0000000 --- a/geeksbot_v2/dmessages/utils.py +++ /dev/null @@ -1,28 +0,0 @@ -from rest_framework.response import Response -from rest_framework import status - - -def create_error_response(msg, status=status.HTTP_404_NOT_FOUND): - return Response({'details': msg}, - status=status) - - -def create_success_response(message_data, status, many: bool = False): - from .serializers import MessageSerializer - - return Response(MessageSerializer(message_data, many=many).data, - status=status) - - -def create_request_success_response(request_data, status, many: bool = False): - from .serializers import AdminRequestSerializer - - return Response(AdminRequestSerializer(request_data, many=many).data, - status=status) - - -def create_comment_success_response(comment_data, status, many: bool = False): - from .serializers import AdminCommentSerializer - - return Response(AdminCommentSerializer(comment_data, many=many).data, - status=status) diff --git a/geeksbot_v2/dmessages/views.py b/geeksbot_v2/dmessages/views.py deleted file mode 100644 index c18433a..0000000 --- a/geeksbot_v2/dmessages/views.py +++ /dev/null @@ -1,180 +0,0 @@ -from time import sleep -from datetime import datetime - -from rest_framework.views import APIView -from rest_framework import status -from rest_framework.permissions import IsAuthenticated -from django.core.exceptions import ObjectDoesNotExist -from rest_framework.response import Response -from rest_framework import status - - -from .models import Message -from .models import AdminComment -from .models import AdminRequest -from .models import GuildInfo -from geeksbot_v2.utils.api_utils import PaginatedAPIView -from .utils import create_error_response -from .utils import create_success_response -from .utils import create_request_success_response -from .utils import create_comment_success_response -from .serializers import AdminRequestSerializer -from .serializers import AdminCommentSerializer - -# Create your views here. - -# API Views - - -class MessagesAPI(PaginatedAPIView): - permission_classes = [IsAuthenticated] - - def get(self, request, format=None): - messages = Message.objects.all() - page = self.paginate_queryset(messages) - if page: - return create_success_response(page, status.HTTP_200_OK, many=True) - return create_success_response(messages, status.HTTP_200_OK, many=True) - - def post(self, request, format=None): - data = dict(request.data) - return Message.add_new_message(data) - - -class MessageDetailAPI(APIView): - permission_classes = [IsAuthenticated] - - def get(self, request, id, format=None): - message = Message.get_message_by_id(id) - if message: - return create_success_response(message, status.HTTP_200_OK, many=False) - else: - return create_error_response("Message Does Not Exist", - status=status.HTTP_404_NOT_FOUND) - - def put(self, request, id, format=None): - data = dict(request.data) - message = Message.get_message_by_id(id) - if message: - return message.update_message(data) - else: - return create_error_response('Message Does Not Exist', - status=status.HTTP_404_NOT_FOUND) - - -class WaitForMessageAPI(APIView): - permission_classes = [IsAuthenticated] - - def get(self, request, id, timeout: int = 3, format=None): - message = Message.get_message_by_id(id) - try_count = 0 - while not message: - sleep(0.1) - try_count += 1 - if try_count > timeout * 10: - return create_error_response("Timeout reached before message is available.", - statu=status.HTTP_404_NOT_FOUND) - message = Message.get_message_by_id(id) - return create_success_response(message, status=status.HTTP_200_OK) - - -class RequestsAPI(PaginatedAPIView): - permission_classes = [IsAuthenticated] - - def get(self, request, guild_id, format=None): - requests = AdminRequest.get_open_requests_by_guild(guild_id) - page = self.paginate_queryset(requests) - if page is not None: - return create_request_success_response(page, status.HTTP_200_OK, many=True) - if requests: - return create_request_success_response(requests, status.HTTP_200_OK, many=True) - return create_error_response("No requests found") - - def post(self, request, guild_id, format=None): - data = dict(request.data) - return AdminRequest.add_new_request(guild_id, data) - - -class UserRequestsAPI(PaginatedAPIView): - permission_classes = [IsAuthenticated] - - def get(self, request, guild_id, author_id, format=None): - requests = AdminRequest.get_open_requests_by_guild_author(guild_id, author_id) - page = self.paginate_queryset(requests) - if page is not None: - return create_request_success_response(page, status.HTTP_200_OK, many=True) - if requests: - return create_request_success_response(requests, status.HTTP_200_OK, many=True) - return create_error_response("No requests found") - - -class RequestDetailAPI(APIView): - permission_classes = [IsAuthenticated] - - def get(self, req, guild_id, request_id, format=None): - req = AdminRequest.get_open_request_by_id(guild_id, request_id) - if req: - comments = AdminComment.get_comments_by_request(req) - if comments: - data = AdminRequestSerializer(req).data - data['comments'] = AdminCommentSerializer(comments, many=True).data - return Response(data, status.HTTP_200_OK) - else: - return create_request_success_response(req, status.HTTP_200_OK, many=False) - else: - return create_error_response("That Request Does Not Exist", - status=status.HTTP_404_NOT_FOUND) - - def put(self, request, guild_id, request_id, format=None): - req = AdminRequest.get_open_request_by_id(guild_id, request_id) - if req: - data = dict(request.data) - return req.update_request(data) - return create_error_response("That Request Does Not Exist", - status=status.HTTP_404_NOT_FOUND) - - def delete(self, request, guild_id, request_id, format=None): - data = dict(request.data) - request = AdminRequest.get_open_request_by_id(guild_id, request_id) - data['completed'] = True - data['completed_at'] = datetime.utcnow() - return request.update_request(data) - - -class CommentsAPI(PaginatedAPIView): - permissions_classes = [IsAuthenticated] - - def get(self, request, guild_id, request_id, format=None): - comments = AdminComment.get_comments_by_request(request_id) - if comments: - return create_comment_success_response(comments, status=status.HTTP_200_OK, many=True) - return create_error_response("No Comments found") - - def post(self, request, guild_id, request_id, format=None): - data = dict(request.data) - return AdminComment.add_new_comment(data, guild_id, request_id) - - -class CommentsCountAPI(PaginatedAPIView): - permissions_classes = [IsAuthenticated] - - def get(self, request, guild_id, request_id, format=None): - comments = AdminComment.get_comments_by_request(request_id) - if comments: - return Response(len(comments), status=status.HTTP_200_OK) - return Response(0, status.HTTP_200_OK) - - -class CommentDetailAPI(APIView): - permissions_classes = [IsAuthenticated] - - def get(self, request, request_id, comment_id, format=None): - comment = AdminComment.get_comment_by_id(comment_id) - if comment: - if comment.request.id != request_id: - return create_error_response("That comment is not for this request", - status=status.HTTP_400_BAD_REQUEST) - return create_comment_success_response(comment, status.HTTP_200_OK, many=False) - else: - return create_error_response("Comment Does Not Exist", - status=status.HTTP_404_NOT_FOUND) diff --git a/geeksbot_v2/entrypoint b/geeksbot_v2/entrypoint deleted file mode 100755 index 06d10b3..0000000 --- a/geeksbot_v2/entrypoint +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/sh - -set -o errexit -set -o pipefail -set -o nounset - -if [ -z "${POSTGRES_USER}" ]; then - base_postgres_image_default_user='postgres' - export POSTGRES_USER="${base_postgres_image_default_user}" -fi - -postgres_ready() { -python << END -import sys - -import psycopg2 - -try: - psycopg2.connect( - dbname="${POSTGRES_DB}", - user="${POSTGRES_USER}", - password="${POSTGRES_PASSWORD}", - host="${POSTGRES_HOST}", - port="${POSTGRES_PORT}", - ) -except psycopg2.OperationalError: - sys.exit(-1) -sys.exit(0) - -END -} -until postgres_ready; do - >&2 echo 'Waiting for PostgreSQL to become available...' - sleep 1 -done ->&2 echo 'PostgreSQL is available' - -python manage.py collectstatic --noinput -python manage.py makemigrations --noinput -python manage.py migrate - -/usr/bin/supervisord -c /etc/supervisor/supervisord.conf diff --git a/geeksbot_v2/guilds/__init__.py b/geeksbot_v2/guilds/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/geeksbot_v2/guilds/admin.py b/geeksbot_v2/guilds/admin.py deleted file mode 100644 index a85e098..0000000 --- a/geeksbot_v2/guilds/admin.py +++ /dev/null @@ -1,8 +0,0 @@ -from django.contrib import admin - -from geeksbot_v2.guilds.models import Guild -from geeksbot_v2.guilds.models import Role - -# Register your models here. -admin.site.register(Guild) -admin.site.register(Role) \ No newline at end of file diff --git a/geeksbot_v2/guilds/api_urls.py b/geeksbot_v2/guilds/api_urls.py deleted file mode 100644 index 6b2f3d7..0000000 --- a/geeksbot_v2/guilds/api_urls.py +++ /dev/null @@ -1,14 +0,0 @@ -from django.urls import path - -from .views import GuildsAPI, GuildDetail -from .views import RolesAPI, RoleDetailAPI -from .views import AdminRolesAPI - -app_name = "guilds_api" -urlpatterns = [ - path("", view=GuildsAPI.as_view(), name="list"), - path("/", view=GuildDetail.as_view(), name='detail'), - path("/roles/", view=RolesAPI.as_view(), name="list"), - path("/roles/admin/", view=AdminRolesAPI.as_view(), name='admin'), - path("/roles//", view=RoleDetailAPI.as_view(), name='detail'), -] diff --git a/geeksbot_v2/guilds/apps.py b/geeksbot_v2/guilds/apps.py deleted file mode 100644 index 6789cc4..0000000 --- a/geeksbot_v2/guilds/apps.py +++ /dev/null @@ -1,7 +0,0 @@ -from django.apps import AppConfig -from django.utils.translation import gettext_lazy as _ - - -class GuildsConfig(AppConfig): - name = 'geeksbot_v2.guilds' - verbose_name = _("Guilds") diff --git a/geeksbot_v2/guilds/migrations/0001_initial.py b/geeksbot_v2/guilds/migrations/0001_initial.py deleted file mode 100644 index cf97b8b..0000000 --- a/geeksbot_v2/guilds/migrations/0001_initial.py +++ /dev/null @@ -1,35 +0,0 @@ -# Generated by Django 2.2.4 on 2019-09-20 21:39 - -import django.contrib.postgres.fields -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ] - - operations = [ - migrations.CreateModel( - name='Guild', - fields=[ - ('id', models.CharField(max_length=30, primary_key=True, serialize=False)), - ('admin_chat', models.CharField(blank=True, max_length=30, null=True)), - ('new_patron_message', models.TextField(blank=True, max_length=1000, null=True)), - ('default_channel', models.CharField(max_length=30)), - ('new_patron_channel', models.CharField(blank=True, max_length=30, null=True)), - ('prefixes', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=10), size=None)), - ], - ), - migrations.CreateModel( - name='Role', - fields=[ - ('id', models.CharField(max_length=30, primary_key=True, serialize=False)), - ('role_type', models.PositiveSmallIntegerField()), - ('guild', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='guilds.Guild')), - ], - ), - ] diff --git a/geeksbot_v2/guilds/migrations/0002_auto_20190921_0250.py b/geeksbot_v2/guilds/migrations/0002_auto_20190921_0250.py deleted file mode 100644 index 49a4932..0000000 --- a/geeksbot_v2/guilds/migrations/0002_auto_20190921_0250.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 2.2.4 on 2019-09-21 02:50 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('guilds', '0001_initial'), - ] - - operations = [ - migrations.RemoveField( - model_name='guild', - name='admin_chat', - ), - migrations.RemoveField( - model_name='guild', - name='default_channel', - ), - migrations.RemoveField( - model_name='guild', - name='new_patron_channel', - ), - ] diff --git a/geeksbot_v2/guilds/migrations/__init__.py b/geeksbot_v2/guilds/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/geeksbot_v2/guilds/models.py b/geeksbot_v2/guilds/models.py deleted file mode 100644 index 56afbac..0000000 --- a/geeksbot_v2/guilds/models.py +++ /dev/null @@ -1,133 +0,0 @@ -import os - -from django.db import models -from django.contrib.postgres.fields import ArrayField -from django.core.exceptions import ObjectDoesNotExist -from rest_framework import status - -from .utils import create_error_response -from .utils import create_success_response -from .utils import create_role_success_response - - -# Create your models here. - - -class Guild(models.Model): - id = models.CharField(max_length=30, primary_key=True) - new_patron_message = models.TextField(max_length=1000, blank=True, null=True) - prefixes = ArrayField(models.CharField(max_length=10)) - - def __str__(self): - return self.id - - def update_guild(self, data): - if data.get('new_patron_message'): - self.new_patron_message = data.get('new_patron_message') - if data.get('add_prefix'): - if data.get('add_prefix') not in self.prefixes: - self.prefixes.append(data.get('add_prefix')) - if data.get('remove_prefix'): - if data.get('remove_prefix') in self.prefixes: - self.prefixes.remove(data.get('remove_prefix')) - if len(self.prefixes) <= 0: - self.prefixes = [os.environ['DISCORD_DEFAULT_PREFIX'], ] - - self.save() - return self - - @classmethod - def get_guild_by_id(cls, id): - try: - return cls.objects.get(id=id) - except ObjectDoesNotExist: - return None - - @classmethod - def create_guild(cls, data): - id = data.get('id') - if not id: - return create_error_response('ID is required', - status=status.HTTP_400_BAD_REQUEST) - - if cls.get_guild_by_id(id): - return create_error_response('That Guild already exists', - status.HTTP_409_CONFLICT) - - guild = cls( - id=id, - prefixes=data.get('prefixes'), - new_patron_message=data.get('new_patron_message') - ) - guild.save() - return create_success_response(guild, status.HTTP_201_CREATED, many=False) - - -class Role(models.Model): - id = models.CharField(max_length=30, primary_key=True) - guild = models.ForeignKey(Guild, on_delete=models.CASCADE, null=False) - role_type = models.PositiveSmallIntegerField() - - def update_role(self, data): - if data.get('role_type'): - self.role_type = data.get('role_type') - - self.save() - return self - - @classmethod - def add_new_role(cls, guild_id, data): - id = data.get('id') - role_type = data.get('role_type') - if not (id and guild_id and (role_type is not None)): - return create_error_response("The Role ID, Guild, and Role Type are required", - status=status.HTTP_400_BAD_REQUEST) - - if cls.get_role_by_id(id): - return create_error_response("That Role Already Exists", - status=status.HTTP_409_CONFLICT) - guild = Guild.get_guild_by_id(guild_id) - if not isinstance(guild, Guild): - return create_error_response("Guild Does Not Exist", - status=status.HTTP_404_NOT_FOUND) - - try: - role_type = int(role_type) - except ValueError: - return create_error_response("Role Type must be a positive number", - status=status.HTTP_400_BAD_REQUEST) - if role_type < 0: - return create_error_response("Role Type must be a positive number", - status=status.HTTP_400_BAD_REQUEST) - elif 1000 < role_type: - return create_error_response("Role Type must be less than 1000", - status=status.HTTP_400_BAD_REQUEST) - - role = cls( - id=id, - guild=guild, - role_type=role_type - ) - role.save() - return create_role_success_response(role, status.HTTP_201_CREATED, many=False) - - @classmethod - def get_role_by_id(cls, guild_id, role_id): - try: - return cls.get_guild_roles(guild_id).get(id=role_id) - except ObjectDoesNotExist: - return None - - @classmethod - def get_guild_roles(cls, guild): - return cls.objects.filter(guild__id=guild) - - @classmethod - def get_admin_roles(cls, guild_id): - try: - return cls.get_guild_roles(guild_id).filter(role_type__gte=90) - except ObjectDoesNotExist: - return None - - def __str__(self): - return f"{self.guild.id} | {self.id}" diff --git a/geeksbot_v2/guilds/permissions.py b/geeksbot_v2/guilds/permissions.py deleted file mode 100644 index 50d64b0..0000000 --- a/geeksbot_v2/guilds/permissions.py +++ /dev/null @@ -1,8 +0,0 @@ -from rest_framework.permissions import BasePermission - -class GuildPermissions(BasePermission): - def has_permission(self, request, view): - return super().has_permission(request, view) - - def has_object_permission(self, request, view, obj): - return super().has_object_permission(request, view, obj) diff --git a/geeksbot_v2/guilds/serializers.py b/geeksbot_v2/guilds/serializers.py deleted file mode 100644 index 78ee353..0000000 --- a/geeksbot_v2/guilds/serializers.py +++ /dev/null @@ -1,16 +0,0 @@ -from rest_framework import serializers - -from geeksbot_v2.guilds.models import Guild -from geeksbot_v2.guilds.models import Role - - -class GuildSerializer(serializers.ModelSerializer): - class Meta: - model = Guild - fields = "__all__" - - -class RoleSerializer(serializers.ModelSerializer): - class Meta: - model = Role - fields = ["id", "guild", "role_type"] diff --git a/geeksbot_v2/guilds/tests.py b/geeksbot_v2/guilds/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/geeksbot_v2/guilds/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/geeksbot_v2/guilds/urls.py b/geeksbot_v2/guilds/urls.py deleted file mode 100644 index e69de29..0000000 diff --git a/geeksbot_v2/guilds/utils.py b/geeksbot_v2/guilds/utils.py deleted file mode 100644 index 78314d8..0000000 --- a/geeksbot_v2/guilds/utils.py +++ /dev/null @@ -1,21 +0,0 @@ -from rest_framework.response import Response -from rest_framework import status - - -def create_error_response(msg, status=status.HTTP_404_NOT_FOUND): - return Response({'details': msg}, - status=status) - - -def create_success_response(guild_data, status, many: bool = False): - from .serializers import GuildSerializer - - return Response(GuildSerializer(guild_data, many=many).data, - status=status) - - -def create_role_success_response(role_data, status, many: bool = False): - from .serializers import RoleSerializer - - return Response(RoleSerializer(role_data, many=many).data, - status=status) diff --git a/geeksbot_v2/guilds/views.py b/geeksbot_v2/guilds/views.py deleted file mode 100644 index e461771..0000000 --- a/geeksbot_v2/guilds/views.py +++ /dev/null @@ -1,133 +0,0 @@ -from rest_framework.views import APIView -from rest_framework import status -from rest_framework.permissions import IsAuthenticated -from django.core.exceptions import ObjectDoesNotExist - -from geeksbot_v2.utils.api_utils import PaginatedAPIView -from .models import Guild -from .models import Role -from .utils import create_error_response -from .utils import create_success_response -from .utils import create_role_success_response - -# Create your views here. - -# API Views - - -class GuildsAPI(PaginatedAPIView): - permission_classes = [IsAuthenticated] - - def get(self, request, format=None): - guilds = Guild.objects.all() - page = self.paginate_queryset(guilds) - if page is not None: - return create_success_response(page, status.HTTP_200_OK, many=True) - - return create_success_response(guilds, status.HTTP_200_OK, many=True) - - def post(self, request, format=None): - data = dict(request.data) - return Guild.create_guild(data) - - -class GuildDetail(APIView): - permission_classes = [IsAuthenticated] - - def get(self, request, id, format=None): - try: - guild = Guild.objects.get(id=id) - except ObjectDoesNotExist: - return create_error_response("Guild Does not Exist", - status=status.HTTP_404_NOT_FOUND) - else: - return create_success_response(guild, - status=status.HTTP_200_OK) - - def put(self, request, id, format=None): - guild = Guild.get_guild_by_id(id) - - if guild: - data = dict(request.data) - guild = guild.update_guild(data) - return create_success_response(guild, - status=status.HTTP_202_ACCEPTED) - else: - return create_error_response('Guild Does Not Exist', - status=status.HTTP_404_NOT_FOUND) - - def delete(self, request, id, format=None): - guild = Guild.get_guild_by_id(id) - - if guild: - # data = dict(request.data) - # TODO Add a check to verify user is allowed to delete... - # Possibly in object permissions... - guild.delete() - return create_success_response(guild, - status=status.HTTP_200_OK) - else: - return create_error_response('Guild Does Not Exist', - status=status.HTTP_404_NOT_FOUND) - - -class RolesAPI(PaginatedAPIView): - permission_classes = [IsAuthenticated] - - def get(self, request, guild_id, format=None): - roles = Role.get_guild_roles(guild_id) - page = self.paginate_queryset(roles) - if page is not None: - return create_success_response(page, status.HTTP_200_OK, many=True) - - return create_success_response(roles, status.HTTP_200_OK, many=True) - - def post(self, request, guild_id, format=None): - data = dict(request.data) - return Role.add_new_role(guild_id, data) - - -class AdminRolesAPI(APIView): - permission_classes = [IsAuthenticated] - - def get(self, request, guild_id, format=None): - roles = Role.get_admin_roles(guild_id) - if roles: - return create_role_success_response(roles, status=status.HTTP_200_OK, many=True) - return create_error_response('There are no admin roles configured', - status=status.HTTP_404_NOT_FOUND) - - def put(self, request, guild_id, format=None): - data = dict(request.data) - role = Role.get_role_by_id(guild_id, data['role']) - if role: - role = role.update_role({'role_type': 100}) - return create_role_success_response(role, status=status.HTTP_202_ACCEPTED) - return create_error_response("That role does not exist", - status=status.HTTP_404_NOT_FOUND) - - -class RoleDetailAPI(APIView): - permission_classes = [IsAuthenticated] - - def get(self, request, guild_id, id, format=None): - try: - role = Role.objects.get(id=id) - except ObjectDoesNotExist: - return create_error_response("Guild Does not Exist", - status=status.HTTP_404_NOT_FOUND) - else: - return create_role_success_response(role, - status=status.HTTP_200_OK) - - def put(self, request, guild_id, id, format=None): - role = Role.get_role_by_id(guild_id, id) - - if role: - data = dict(request.data) - role = role.update_role(data) - return create_role_success_response(role, - status=status.HTTP_202_ACCEPTED) - else: - return create_error_response('Guild Does Not Exist', - status=status.HTTP_404_NOT_FOUND) diff --git a/geeksbot_v2/manage.py b/geeksbot_v2/manage.py deleted file mode 100755 index 31df531..0000000 --- a/geeksbot_v2/manage.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python -import os -import sys - -if __name__ == "__main__": - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "geeksbot_v2.config.settings.local") - - try: - from django.core.management import execute_from_command_line - except ImportError: - # The above import may fail for some other reason. Ensure that the - # issue is really that Django is missing to avoid masking other - # exceptions on Python 2. - try: - import django # noqa - except ImportError: - raise ImportError( - "Couldn't import Django. Are you sure it's installed and " - "available on your PYTHONPATH environment variable? Did you " - "forget to activate a virtual environment?" - ) - - raise - - # This allows easy placement of apps within the interior - # geeksbot_v2 directory. - current_path = os.path.dirname(os.path.abspath(__file__)) - sys.path.append(os.path.join(current_path, "geeksbot_v2")) - - execute_from_command_line(sys.argv) diff --git a/geeksbot_v2/patreon/__init__.py b/geeksbot_v2/patreon/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/geeksbot_v2/patreon/admin.py b/geeksbot_v2/patreon/admin.py deleted file mode 100644 index 6e73988..0000000 --- a/geeksbot_v2/patreon/admin.py +++ /dev/null @@ -1,9 +0,0 @@ -from django.contrib import admin - - -from .models import PatreonCreator -from .models import PatreonTier - -# Register your models here. -admin.site.register(PatreonCreator) -admin.site.register(PatreonTier) \ No newline at end of file diff --git a/geeksbot_v2/patreon/apps.py b/geeksbot_v2/patreon/apps.py deleted file mode 100644 index 5544439..0000000 --- a/geeksbot_v2/patreon/apps.py +++ /dev/null @@ -1,7 +0,0 @@ -from django.apps import AppConfig -from django.utils.translation import gettext_lazy as _ - - -class PatreonConfig(AppConfig): - name = 'geeksbot_v2.patreon' - verbose_name = _("Patreon") diff --git a/geeksbot_v2/patreon/migrations/0001_initial.py b/geeksbot_v2/patreon/migrations/0001_initial.py deleted file mode 100644 index 6abcf6e..0000000 --- a/geeksbot_v2/patreon/migrations/0001_initial.py +++ /dev/null @@ -1,37 +0,0 @@ -# Generated by Django 2.2.4 on 2019-09-20 21:39 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('guilds', '0001_initial'), - ] - - operations = [ - migrations.CreateModel( - name='PatreonCreator', - fields=[ - ('creator', models.CharField(max_length=50, primary_key=True, serialize=False)), - ('link', models.CharField(max_length=100, unique=True)), - ('guilds', models.ManyToManyField(to='guilds.Guild')), - ], - ), - migrations.CreateModel( - name='PatreonTier', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=50)), - ('description', models.TextField()), - ('amount', models.IntegerField(null=True)), - ('creator', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='patreon.PatreonCreator')), - ('guild', models.ManyToManyField(to='guilds.Guild')), - ('next_lower_tier', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='patreon.PatreonTier')), - ('role', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='guilds.Role')), - ], - ), - ] diff --git a/geeksbot_v2/patreon/migrations/__init__.py b/geeksbot_v2/patreon/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/geeksbot_v2/patreon/models.py b/geeksbot_v2/patreon/models.py deleted file mode 100644 index 2952305..0000000 --- a/geeksbot_v2/patreon/models.py +++ /dev/null @@ -1,164 +0,0 @@ -from django.db import models -from django.core.exceptions import ObjectDoesNotExist -from rest_framework import status - -from geeksbot_v2.guilds.models import Guild -from geeksbot_v2.guilds.models import Role -from .utils import create_error_response -from .utils import create_success_creator_response -from .utils import create_success_tier_response - -# Create your models here. - - -class PatreonCreator(models.Model): - guilds = models.ManyToManyField(Guild) - creator = models.CharField(max_length=50, null=False, primary_key=True) - link = models.CharField(max_length=100, null=False, unique=True) - - def update_creator(self, data): - if data.get('guild'): - guild = Guild.get_guild_by_id(data.get('guild')) - if not isinstance(guild, Guild): - return create_error_response('Guild Does Not Exist', - status=status.HTTP_404_NOT_FOUND) - self.guilds.add(guild) - if data.get('link'): - self.link = data.get('link') - - self.save() - return create_success_creator_response(self, status.HTTP_202_ACCEPTED, many=False) - - @classmethod - def add_new_creator(cls, data): - creator = data.get('creator') - if PatreonCreator.get_creator_by_name(creator): - return create_error_response('That Creator already exists', - status=status.HTTP_409_CONFLICT) - link = data.get('link') - if not (creator and link): - return create_error_response('Creator and Link are both required fields', - status=status.HTTP_400_BAD_REQUEST) - guild = Guild.get_guild_by_id(data.get('guild')) - if not guild: - return create_error_response('A Valid Guild is required', - status=status.HTTP_400_BAD_REQUEST) - - new_creator = cls( - creator=creator, - link=link - ) - new_creator.save() - new_creator.guilds.add(guild) - return create_success_creator_response(new_creator, status.HTTP_201_CREATED, many=False) - - @classmethod - def get_creator_by_name(cls, name): - try: - return cls.objects.get(creator=name) - except ObjectDoesNotExist: - return None - - def __str__(self): - return f"{self.guild.id} | {self.creator}" - - -class PatreonTier(models.Model): - creator = models.ForeignKey(PatreonCreator, on_delete=models.CASCADE) - guild = models.ManyToManyField(Guild) - name = models.CharField(max_length=50) - description = models.TextField() - role = models.ForeignKey(Role, on_delete=models.CASCADE) - amount = models.IntegerField(null=True) - next_lower_tier = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True) - - def update_tier(self, data): - if data.get('guild'): - guild = Guild.get_guild_by_id(data.get('guild')) - if not isinstance(guild, Guild): - return create_error_response('Guild Does Not Exist', - status=status.HTTP_404_NOT_FOUND) - self.guilds.add(guild) - if data.get('name'): - self.name = data.get('name') - if data.get('description'): - self.description = data.get('description') - if data.get('role'): - role = Role.get_role_by_id(data.get('role')) - if not isinstance(role, Role): - return create_error_response('Role Does Not Exist', - status=status.HTTP_404_NOT_FOUND) - self.role = role - if data.get('amount'): - self.amount = data.get('amount') - if data.get('next_lower_tier'): - tier = self.get_tier_by_id(data.get('next_lower_tier')) - if not isinstance(tier, self.__class__): - return create_error_response('Next Lower Tier Does Not Exist', - status=status.HTTP_404_NOT_FOUND) - self.next_lower_tier = tier - - self.save() - return create_success_tier_response(tier, status.HTTP_202_ACCEPTED, many=False) - - @classmethod - def get_tier_by_id(cls, id): - try: - return cls.objects.get(id=id) - except ObjectDoesNotExist: - return None - - @classmethod - def add_new_tier(cls, data): - creator_str = data.get('creator') - guild_id = data.get('guild') - name = data.get('name') - description = data.get('description') - role_id = data.get('role') - next_lower_tier_id = data.get('next_lower_tier') - if not (creator_str and guild_id and name and description and role_id): - return create_error_response("The Creator's name, Guild, Tier name, Description, " - "and Discord Role are all required.", - status=status.HTTP_400_BAD_REQUEST) - creator = PatreonCreator.get_creator_by_name(creator_str) - if not isinstance(creator, PatreonCreator): - return create_error_response("Creator Does Not Exist", - status=status.HTTP_404_NOT_FOUND) - guild = Guild.get_guild_by_id(guild_id) - if not isinstance(guild, Guild): - return create_error_response("Guild Does Not Exist", - status=status.HTTP_404_NOT_FOUND) - role = Role.get_role_by_id(role_id) - if not isinstance(role, Role): - return create_error_response("Role Does Not Exist", - status=status.HTTP_404_NOT_FOUND) - if next_lower_tier_id: - next_lower_tier = cls.get_tier_by_id(next_lower_tier_id) - if not isinstance(next_lower_tier, cls): - return create_error_response("Next Lower Tier Does Not Exist", - status=status.HTTP_404_NOT_FOUND) - if next_lower_tier.guild != guild: - return create_error_response("The given next lower tier is not for the same guild.", - status=status.HTTP_400_BAD_REQUEST) - if next_lower_tier.creator != creator: - return create_error_response("The given next lower tier is not for the same creator.", - status=status.HTTP_400_BAD_REQUEST) - try: - PatreonTier.objects.filter(creator=creator, guilds__id=guild.id).get(name=name) - except ObjectDoesNotExist: - tier = cls( - creator=creator, - name=name, - description=description, - role=role, - amount=data.get('amount'), - next_lower_tier=next_lower_tier if next_lower_tier_id else None - ) - tier.save() - return create_success_tier_response(tier, status.HTTP_201_CREATED, many=False) - else: - return create_error_response("A Tier with that name already exists for that creator in this guild.", - status=status.HTTP_409_CONFLICT) - - def __str__(self): - return f"{self.guild.id} | {self.creator.creator} | {self.name}" diff --git a/geeksbot_v2/patreon/patron.py b/geeksbot_v2/patreon/patron.py deleted file mode 100644 index 6a4e430..0000000 --- a/geeksbot_v2/patreon/patron.py +++ /dev/null @@ -1,77 +0,0 @@ -import discord -import gspread -from oauth2client.service_account import ServiceAccountCredentials - - -class Patron: - def __init__(self, *, discord_name: str=None, steam_id: int=None, patreon_tier: str=None, patron_of: str=None, - discord_discrim: int=None, discord_id: int=None, patreon_name: str=None, steam_name: str=None): - self.discord_name = discord_name - self.discord_discrim = discord_discrim - self.steam_id = steam_id - self.discord_id = discord_id - self.patreon_tier = patreon_tier - self.patron_of = patron_of - self.patreon_name = patreon_name - self.steam_name = steam_name - - @classmethod - async def from_id(cls, bot, steam_id: int, *, discord_id: int=None): - scope = ['https://spreadsheets.google.com/feeds', - 'https://www.googleapis.com/auth/drive'] - credentials = ServiceAccountCredentials.from_json_keyfile_dict(bot.google_secret, scope) - - gc = gspread.authorize(credentials) - sh = gc.open_by_key(bot.bot_secrets['sheet']) - ws = sh.worksheet('Current Whitelist') - try: - cell = ws.find(f'{steam_id}') - except gspread.CellNotFound: - return -1 - else: - steam_name = None - if discord_id: - user_ref = bot.fs_db.document(f'users/{discord_id}') - user_info = (await bot.loop.run_in_executor(bot.tpe, user_ref.get)).to_dict() - if user_info: - steam_name = user_info.get('steam_name') - row = ws.row_values(cell.row) - return cls(patreon_name=row[1], - discord_name=row[2], - steam_id=row[5], - patreon_tier=row[4].split(' (')[1].strip(')') if len(row[4].split(' (')) > 1 else row[4], - patron_of=row[3].split(' (')[0], - discord_id=discord_id, - steam_name=steam_name) - - @classmethod - async def from_name(cls, bot, discord_name: discord.Member, *, discord_id: int=None): - scope = ['https://spreadsheets.google.com/feeds', - 'https://www.googleapis.com/auth/drive'] - credentials = ServiceAccountCredentials.from_json_keyfile_dict(bot.google_secret, scope) - - gc = gspread.authorize(credentials) - sh = gc.open_by_key(bot.bot_secrets['sheet']) - ws = sh.worksheet('Current Whitelist') - try: - cell = ws.find(f'{discord_name.name if isinstance(discord_name, discord.Member) else discord_name}') - except gspread.CellNotFound: - try: - cell = ws.find(f'{discord_name.nick if isinstance(discord_name, discord.Member) else discord_name}') - except gspread.CellNotFound: - return -1 - steam_name = None - discord_id = discord_name.id if isinstance(discord_name, discord.Member) else discord_id - if discord_id: - user_ref = bot.fs_db.document(f'users/{discord_id}') - user_info = (await bot.loop.run_in_executor(bot.tpe, user_ref.get)).to_dict() - if user_info: - steam_name = user_info.get('steam_name') - row = ws.row_values(cell.row) - return cls(patreon_name=row[1], - discord_name=row[2], - discord_id=discord_id, - steam_id=row[5], - patreon_tier=row[4].split(' (')[1].strip(')') if len(row[4].split(' (')) > 1 else row[4], - patron_of=row[3].split(' (')[0], - steam_name=steam_name) diff --git a/geeksbot_v2/patreon/serializers.py b/geeksbot_v2/patreon/serializers.py deleted file mode 100644 index 818c942..0000000 --- a/geeksbot_v2/patreon/serializers.py +++ /dev/null @@ -1,16 +0,0 @@ -from rest_framework import serializers - -from geeksbot_v2.patreon.models import PatreonCreator -from geeksbot_v2.patreon.models import PatreonTier - - -class PatreonCreatorSerializer(serializers.ModelSerializer): - class Meta: - model = PatreonCreator - fields = "__all__" - - -class PatreonTierSerializer(serializers.ModelSerializer): - class Meta: - model = PatreonTier - fields = "__all__" diff --git a/geeksbot_v2/patreon/tests.py b/geeksbot_v2/patreon/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/geeksbot_v2/patreon/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/geeksbot_v2/patreon/utils.py b/geeksbot_v2/patreon/utils.py deleted file mode 100644 index c738729..0000000 --- a/geeksbot_v2/patreon/utils.py +++ /dev/null @@ -1,21 +0,0 @@ -from rest_framework.response import Response -from rest_framework import status - - -def create_error_response(msg, status=status.HTTP_404_NOT_FOUND): - return Response({'details': msg}, - status=status) - - -def create_success_creator_response(creator_data, status, many: bool = False): - from .serializers import PatreonCreatorSerializer - - return Response(PatreonCreatorSerializer(creator_data, many=many).data, - status=status) - - -def create_success_tier_response(tier_data, status, many: bool = False): - from .serializers import PatreonTierSerializer - - return Response(PatreonTierSerializer(tier_data, many=many).data, - status=status) diff --git a/geeksbot_v2/patreon/views.py b/geeksbot_v2/patreon/views.py deleted file mode 100644 index 91ea44a..0000000 --- a/geeksbot_v2/patreon/views.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.shortcuts import render - -# Create your views here. diff --git a/geeksbot_v2/rcon/__init__.py b/geeksbot_v2/rcon/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/geeksbot_v2/rcon/admin.py b/geeksbot_v2/rcon/admin.py deleted file mode 100644 index 7209c51..0000000 --- a/geeksbot_v2/rcon/admin.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.contrib import admin - -from .models import RconServer - -# Register your models here. -admin.site.register(RconServer) \ No newline at end of file diff --git a/geeksbot_v2/rcon/api_urls.py b/geeksbot_v2/rcon/api_urls.py deleted file mode 100644 index 6496d3c..0000000 --- a/geeksbot_v2/rcon/api_urls.py +++ /dev/null @@ -1,10 +0,0 @@ -from django.urls import path - -from .views import RCONServersAPI, RCONServerDetailAPI, ListPlayers - -app_name = "rcon_api" -urlpatterns = [ - path("/", view=RCONServersAPI.as_view(), name='guild_servers'), - path("//", view=RCONServerDetailAPI.as_view(), name="server_detail"), - path("//listplayers", view=ListPlayers.as_view(), name='listplayers'), -] diff --git a/geeksbot_v2/rcon/apps.py b/geeksbot_v2/rcon/apps.py deleted file mode 100644 index c6d1290..0000000 --- a/geeksbot_v2/rcon/apps.py +++ /dev/null @@ -1,7 +0,0 @@ -from django.apps import AppConfig -from django.utils.translation import gettext_lazy as _ - - -class RconConfig(AppConfig): - name = 'geeksbot_v2.rcon' - verbose_name = _("Rcon") diff --git a/geeksbot_v2/rcon/migrations/0001_initial.py b/geeksbot_v2/rcon/migrations/0001_initial.py deleted file mode 100644 index ea652ae..0000000 --- a/geeksbot_v2/rcon/migrations/0001_initial.py +++ /dev/null @@ -1,35 +0,0 @@ -# Generated by Django 2.2.4 on 2019-09-20 21:39 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('guilds', '0001_initial'), - ('dmessages', '0001_initial'), - ('channels', '0001_initial'), - ] - - operations = [ - migrations.CreateModel( - name='RconServer', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=50)), - ('ip', models.GenericIPAddressField()), - ('port', models.PositiveIntegerField()), - ('password', models.CharField(max_length=50)), - ('monitor_chat', models.BooleanField()), - ('alerts_channel', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='channels.Channel')), - ('guild', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='guilds.Guild')), - ('info_channel', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='channels.Channel')), - ('info_message', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='dmessages.Message')), - ('monitor_chat_channel', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='channels.Channel')), - ('settings_message', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='dmessages.Message')), - ], - ), - ] diff --git a/geeksbot_v2/rcon/migrations/0002_rconserver_whitelist.py b/geeksbot_v2/rcon/migrations/0002_rconserver_whitelist.py deleted file mode 100644 index 9b5aa20..0000000 --- a/geeksbot_v2/rcon/migrations/0002_rconserver_whitelist.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 2.2.4 on 2019-09-20 21:39 - -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('rcon', '0001_initial'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.AddField( - model_name='rconserver', - name='whitelist', - field=models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL), - ), - ] diff --git a/geeksbot_v2/rcon/migrations/__init__.py b/geeksbot_v2/rcon/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/geeksbot_v2/rcon/models.py b/geeksbot_v2/rcon/models.py deleted file mode 100644 index fc0ed3b..0000000 --- a/geeksbot_v2/rcon/models.py +++ /dev/null @@ -1,128 +0,0 @@ -from django.db import models -from django.core.exceptions import ObjectDoesNotExist -from rest_framework import status - -from geeksbot_v2.guilds.models import Guild -from geeksbot_v2.dmessages.models import Message -from geeksbot_v2.users.models import User -from geeksbot_v2.channels.models import Channel -from .utils import create_error_response -from .utils import create_success_response - -# Create your models here. - - -class RconServer(models.Model): - guild = models.ForeignKey(Guild, on_delete=models.CASCADE) - name = models.CharField(max_length=50) - ip = models.GenericIPAddressField() - port = models.PositiveIntegerField() - password = models.CharField(max_length=50) - monitor_chat = models.BooleanField() - monitor_chat_channel = models.ForeignKey( - Channel, on_delete=models.DO_NOTHING, related_name="+", null=True, blank=True, default=None - ) - alerts_channel = models.ForeignKey( - Channel, on_delete=models.DO_NOTHING, related_name="+", null=True, blank=True, default=None - ) - info_channel = models.ForeignKey( - Channel, on_delete=models.DO_NOTHING, related_name="+", null=True, blank=True, default=None - ) - info_message = models.ForeignKey( - Message, on_delete=models.DO_NOTHING, related_name="+", null=True, blank=True, default=None - ) - settings_message = models.ForeignKey( - Message, on_delete=models.DO_NOTHING, related_name="+", null=True, blank=True, default=None - ) - whitelist = models.ManyToManyField(User, blank=True) - - def update_server(self, data): - if data.get('name'): - self.name = data.get('name') - if data.get('ip'): - self.ip = data.get('ip') - if data.get('port'): - self.port = data.get('port') - if data.get('password'): - self.password = data.get('password') - if data.get('monitor_chat'): - self.monitor_chat = data.get('monitor_chat') - if 'monitor_chat_channel' in data.keys(): - self.monitor_chat_channel = Channel.get_channel_by_id(data.get('monitor_chat_channel')) - if 'alerts_channel' in data.keys(): - self.alerts_channel = Channel.get_channel_by_id(data.get('alerts_channel')) - if 'info_channel' in data.keys(): - self.alerts_channel = Channel.get_channel_by_id(data.get('info_channel')) - if 'info_message' in data.keys(): - self.info_message = Message.get_message_by_id(data.get('info_message')) - if 'settings_message' in data.keys(): - self.settings_message = Message.get_message_by_id(data.get('settings_message')) - - self.save() - return create_success_response(self, status.HTTP_202_ACCEPTED, many=False) - - def add_whitelist(self, user_id): - user = User.get_user_by_id(user_id) - if not isinstance(user, User): - return create_error_response("User Does Not Exist", - status=status.HTTP_404_NOT_FOUND) - if not user.steam_id: - return create_error_response("User does not have a Steam 64ID attached to their account", - status=status.HTTP_406_NOT_ACCEPTABLE) - self.whitelist.add(user) - return create_error_response("User has been added to the whitelist", - status=status.HTTP_200_OK) - - def remove_from_whitelist(self, user_id): - user = User.get_user_by_id(user_id) - if not isinstance(user, User): - return create_error_response("User Does Not Exist", - status=status.HTTP_404_NOT_FOUND) - self.whitelist.remove(user) - return create_error_response("User has been removed from the whitelist", - status=status.HTTP_200_OK) - - @classmethod - def add_new_server(cls, data): - guild_id = data.get('guild') - name = data.get('name') - ip = data.get('ip') - port = data.get('port') - password = data.get('password') - if not (guild_id and name and ip and port and password): - return create_error_response("One or more of the required fields are missing", - status=status.HTTP_400_BAD_REQUEST) - guild = Guild.get_guild_by_id(guild_id) - if not isinstance(guild, Guild): - return create_error_response("Guild Does Not Exist", - status=status.HTTP_404_NOT_FOUND) - server = cls( - guild=guild, - name=name, - ip=ip, - port=port, - password=password, - monitor_chat=data.get('monitor_chat', False) - ) - server.save() - return create_success_response(server, status.HTTP_201_CREATED, many=False) - - @classmethod - def get_server(cls, guild_id, name): - guild_servers = cls.get_guild_servers(guild_id) - if guild_servers: - try: - return guild_servers.get(name=name) - except ObjectDoesNotExist: - return None - return None - - @classmethod - def get_guild_servers(cls, guild_id): - guild = Guild.get_guild_by_id(guild_id) - if not isinstance(guild, Guild): - return None - return cls.objects.filter(guild=guild) - - def __str__(self): - return f"{self.guild.id} | {self.name}" diff --git a/geeksbot_v2/rcon/rcon_lib/__init__.py b/geeksbot_v2/rcon/rcon_lib/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/geeksbot_v2/rcon/rcon_lib/arcon.py b/geeksbot_v2/rcon/rcon_lib/arcon.py deleted file mode 100644 index 71d776a..0000000 --- a/geeksbot_v2/rcon/rcon_lib/arcon.py +++ /dev/null @@ -1,118 +0,0 @@ -from . import rcon -import asyncio -from typing import Union -import logging - -arcon_log = logging.getLogger('arcon_lib') - - -class ARKServer(rcon.RCONConnection): - def __init__(self, *args, monitor_chat: bool=False, server_chat_channel: int=None, - server_messages_channel: int=None, **kwargs): - self.monitor_chat = monitor_chat - self.server_chat_channel = server_chat_channel - self.server_messages_channel = server_messages_channel - super().__init__(*args, **kwargs) - - async def run_command(self, command: str, multi_packet: bool=False, reconnect_counter: int=0) \ - -> Union[rcon.RCONPacket, str]: - arcon_log.debug(f'Command requested: {command}') - if self.authenticated: - packet = rcon.RCONPacket(next(self.packet_id), rcon.SERVERDATA_EXECCOMMAND, command) - with await self.lock: - try: - arcon_log.debug(f'Sending packet {packet.packet_id}') - await self.send_packet(packet) - arcon_log.debug(f'Packet Sent.') - except ConnectionResetError: - arcon_log.info(f'Connection to {self.host}:{self.port} lost, Reconnecting...') - self.lock.release() - await self._reconnect_and_resend(packet) - await self.lock.acquire() - finally: - arcon_log.debug(f'Waiting for response to packet {packet.packet_id}') - try: - response = await self.read(packet, multi_packet=multi_packet) - except asyncio.TimeoutError as e: - if reconnect_counter > 5: - return 'Reached max reconnects. Closing connection.' - arcon_log.warning(f'No response received: {e}\nAttempting to reconnect #{reconnect_counter}') - self.lock.release() - await self._reconnect() - await self.lock.acquire() - response = await self.run_command(command=command, multi_packet=multi_packet, - reconnect_counter=reconnect_counter + 1) - arcon_log.debug(f'Response Received:\n{response.packet_type}:{response.packet_id}:{response.body}') - response.body = response.body.strip('\x00\x00').strip() - return response - else: - return 'Server is not Authenticated. Please let the Admin know of this issue.' - - async def getchat(self) -> str: - response = await self.run_command(command='getchat', multi_packet=True) - return response.body if isinstance(response, rcon.RCONPacket) else response - - async def saveworld(self) -> str: - response = await self.run_command(command='saveworld') - return response.body if isinstance(response, rcon.RCONPacket) else response - - async def serverchat(self, message: str) -> str: - response = await self.run_command(command=f'serverchat {message}') - return response.body if isinstance(response, rcon.RCONPacket) else response - - async def broadcast(self, message: str) -> str: - response = await self.run_command(command=f'broadcast {message}') - return response.body if isinstance(response, rcon.RCONPacket) else response - - async def listplayers(self) -> str: - response = await self.run_command(command=f'listplayers') - return response.body if isinstance(response, rcon.RCONPacket) else response - - async def whitelist(self, steam_id: str) -> str: - response = await self.run_command(command=f'AllowPlayerToJoinNoCheck {steam_id}') - return response.body if isinstance(response, rcon.RCONPacket) else response - - async def ban_player(self, steam_id: int) -> str: - response = await self.run_command(command=f'BanPlayer {steam_id}') - return response.body if isinstance(response, rcon.RCONPacket) else response - - async def unban_player(self, steam_id: int) -> str: - response = await self.run_command(command=f'UnbanPlayer {steam_id}') - return response.body if isinstance(response, rcon.RCONPacket) else response - - async def kick_player(self, steam_id: int) -> str: - response = await self.run_command(command=f'KickPlayer {steam_id}') - return response.body if isinstance(response, rcon.RCONPacket) else response - - async def stop_server(self) -> int: - saved = await self.saveworld() - if saved == 'World Saved': - await self.serverchat(saved) - await asyncio.sleep(10) - response = await self.run_command(command='DoExit') - if response.body == 'Exiting...': - return 0 - else: - return 2 - else: - return 1 - - async def get_logs(self): - response = await self.run_command(command=f'GetGameLog', multi_packet=True) - return response.body if isinstance(response, rcon.RCONPacket) else response - - async def server_chat_to_steam_id(self, steam_id: int, message: str) -> str: - response = await self.run_command(command=f'ServerChatTo {steam_id} {message}') - return response.body if isinstance(response, rcon.RCONPacket) else response - - async def server_chat_to_player_name(self, player_name: str, message: str) -> str: - response = await self.run_command(command=f'ServerChatToPlayer "{player_name}" {message}') - return response.body if isinstance(response, rcon.RCONPacket) else response - - async def set_time_of_day(self, hour: int, minute: int=00, seconds: int=00) -> str: - response = await self.run_command(command=f'SetTimeOfDay {hour}:{minute}:{seconds}') - return response.body if isinstance(response, rcon.RCONPacket) else response - - async def destroy_wild_dinos(self): - response = await self.run_command(command='DestroyWildDinos') - return response.body if isinstance(response, rcon.RCONPacket) else response diff --git a/geeksbot_v2/rcon/rcon_lib/rcon.py b/geeksbot_v2/rcon/rcon_lib/rcon.py deleted file mode 100644 index deeafee..0000000 --- a/geeksbot_v2/rcon/rcon_lib/rcon.py +++ /dev/null @@ -1,183 +0,0 @@ -import asyncio -import logging -import itertools -import struct - -# Packet types -SERVERDATA_AUTH = 3 -SERVERDATA_AUTH_RESPONSE = 2 -SERVERDATA_EXECCOMMAND = 2 -SERVERDATA_RESPONSE_VALUE = 0 - -__all__ = ['RCONPacket', 'RCONConnection'] - -rcon_log = logging.getLogger('rcon_lib') - - -class RCONPacket: - def __init__(self, packet_id: int=0, packet_type: int=-1, body: str=''): - self.packet_id = packet_id - self.packet_type = packet_type - self.body = body - - def __str__(self): - """Return the body of the packet""" - return self.body - - def size(self): - """Return the size of the packet""" - return len(self.body) + 10 - - def pack(self): - """Return the packed packet""" - return struct.pack(f'<3i{len(self.body) + 2}s', - self.size(), - self.packet_id, - self.packet_type, - bytearray(self.body, 'utf-8')) - - -class RCONConnection: - """Connection to an RCON server""" - - def __init__(self, host: str, port: int, password: str='', single_packet: bool=False, loop=None): - """Create a New RCON Connection - - Parameters: - host (str): The hostname or IP address of the server to connect to - port (int): The port to connect to on the server - password (str): The password to authenticate with the server - single_packet (bool): True for servers who don't give 0 length SERVERDATA_RESPONSE_VALUE requests - """ - - self.host = host - self.port = port - self.password = password - self.single_packet = single_packet - self.packet_id = itertools.count(1) - self.loop = loop or asyncio.get_event_loop() - self.reader = None - self.writer = None - self.lock = asyncio.Lock() - self.authenticated = False - - async def connect(self): - """Returns -1 if connection times out - Returns 1 if connection and auth are successful - Returns 0 if auth fails""" - try: - rcon_log.debug(f'Connecting to {self.host}:{self.port}...') - self.reader, self.writer = await asyncio.open_connection(self.host, self.port, loop=self.loop) - except TimeoutError as e: - rcon_log.error(f'Timeout error: {e}') - return -1 - else: - rcon_log.debug('Connected. Attempting to Authenticate...') - auth_packet = RCONPacket(next(self.packet_id), SERVERDATA_AUTH, self.password) - with await self.lock: - await self.send_packet(auth_packet) - response = await self.read() - if response.packet_type == SERVERDATA_AUTH_RESPONSE and response.packet_id != -1: - rcon_log.debug(f'Authorized {response.packet_type}:{response.packet_id}:{response.body}') - self.authenticated = True - return 1 - else: - rcon_log.debug(f'Not Authorized {response.packet_type}:{response.packet_id}:{response.body}') - self.authenticated = False - return 0 - - async def _reconnect(self): - self.writer = None - self.reader = None - connected = await self.connect() - rcon_log.info(f'Connection completed with a return of {connected}') - if connected != -1: - rcon_log.info('Connected') - else: - rcon_log.warning('Connection Failed') - return connected - - async def _reconnect_and_resend(self, packet): - connected = await self._reconnect() - if connected != -1: - await asyncio.sleep(0.1) - rcon_log.info(f'Re-sending packet {packet.packet_id}') - await self.send_packet(packet) - rcon_log.info(f'Packet Sent.') - return connected - else: - return connected - - async def keep_alive(self): - while True: - await asyncio.sleep(60) - ka_packet = RCONPacket(next(self.packet_id), SERVERDATA_EXECCOMMAND, '') - try: - with await self.lock: - await asyncio.wait_for(self.send_packet(ka_packet), 10, loop=self.loop) - await asyncio.wait_for(self.read(ka_packet), 10, loop=self.loop) - except asyncio.TimeoutError: - self.reader = None - self.writer = None - await self.connect() - - async def send_packet(self, packet): - if packet.size() > 4096: - rcon_log.error('Packet Size is larger than 4096 bytes. Cannot send packet.') - raise RuntimeWarning('Packet Size is larger than 4096 bytes. Cannot send packet.') - if self.writer is None: - await self.connect() - rcon_log.debug(f'Sending Packet {packet.packet_id}: {packet.pack() if packet.packet_type is not SERVERDATA_AUTH else "Censored for Password Security."}') - self.writer.write(packet.pack()) - await self.writer.drain() - rcon_log.debug(f'Packet {packet.packet_id} Sent.') - - async def read(self, request: RCONPacket=None, multi_packet=False) -> RCONPacket: - rcon_log.debug(f'Waiting to receive response to packet {request.packet_id if request else None}') - response = RCONPacket() - try: - if request: - while response.packet_id != request.packet_id and response.packet_id < request.packet_id: - if multi_packet: - if request is None: - rcon_log.warning('A request packet is required to receive a multi packet response') - raise ValueError('A request packet is required to receive a multi packet response') - await asyncio.sleep(.01) - response = await self._receive_multi_packet() - rcon_log.debug(f'Received Multi-Packet response to packet {request.packet_id}:\n' - f'{response.packet_type}:{response.packet_id}:{response.body}') - else: - response = await self.receive_packet() - rcon_log.debug(f'Received Single-Packet response to packet {request.packet_id}:\n' - f'{response.packet_type}:{response.packet_id}:{response.body}') - else: - response = await self.receive_packet() - rcon_log.debug(f'Received Single-Packet response:\n' - f'{response.packet_type}:{response.packet_id}:{response.body}') - except struct.error as e: - rcon_log.error(f'Struct Error: {e}') - response = RCONPacket(body='Error receiving data from the server. Attempting to reconnect. ' - 'Please try again in a little bit.') - self.lock.release() - await self._reconnect() - await self.lock.acquire() - except AttributeError as e: - rcon_log.error(f'Attribute Error: {e}') - response = RCONPacket(body='Error receiving data from the server. Attempting to reconnect. ' - 'Please try again in a little bit.') - self.lock.release() - await self._reconnect() - await self.lock.acquire() - return response - - async def receive_packet(self): - header = await self.reader.read(struct.calcsize('<3i')) - (packet_size, packet_id, packet_type) = struct.unpack('<3i', header) - body = await self.reader.read(packet_size - 8) - return RCONPacket(packet_id, packet_type, body.decode('ascii')) - - async def _receive_multi_packet(self): - header = await self.reader.read(struct.calcsize('<3i')) - (packet_size, packet_id, packet_type) = struct.unpack('<3i', header) - body = await self.reader.readuntil(separator=b'\x00\x00') - return RCONPacket(packet_id, packet_type, body.decode('ascii')) diff --git a/geeksbot_v2/rcon/serializers.py b/geeksbot_v2/rcon/serializers.py deleted file mode 100644 index 18184e3..0000000 --- a/geeksbot_v2/rcon/serializers.py +++ /dev/null @@ -1,9 +0,0 @@ -from rest_framework import serializers - -from geeksbot_v2.rcon.models import RconServer - - -class RconServerSerializer(serializers.ModelSerializer): - class Meta: - model = RconServer - fields = "__all__" diff --git a/geeksbot_v2/rcon/tests.py b/geeksbot_v2/rcon/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/geeksbot_v2/rcon/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/geeksbot_v2/rcon/utils.py b/geeksbot_v2/rcon/utils.py deleted file mode 100644 index 1d78983..0000000 --- a/geeksbot_v2/rcon/utils.py +++ /dev/null @@ -1,19 +0,0 @@ -from rest_framework.response import Response -from rest_framework import status - - -def create_error_response(msg, status=status.HTTP_404_NOT_FOUND): - return Response({'details': msg}, - status=status) - - -def create_success_response(rcon_data, status, many: bool = False): - from .serializers import RconServerSerializer - - return Response(RconServerSerializer(rcon_data, many=many).data, - status=status) - - -def create_rcon_response(message, status): - msg_list = message.split('\n') - return Response(msg_list, status=status) diff --git a/geeksbot_v2/rcon/views.py b/geeksbot_v2/rcon/views.py deleted file mode 100644 index 1d99e76..0000000 --- a/geeksbot_v2/rcon/views.py +++ /dev/null @@ -1,78 +0,0 @@ -import asyncio - -from rest_framework.views import APIView -from rest_framework.permissions import IsAuthenticated -from rest_framework.response import Response -from rest_framework import status -from .rcon_lib import arcon - -from .models import RconServer -from .utils import create_error_response, create_success_response, create_rcon_response -from geeksbot_v2.utils.api_utils import PaginatedAPIView -from .serializers import RconServerSerializer - -# Create your views here. - -# API Views - - -class RCONServersAPI(PaginatedAPIView): - permission_classes = [IsAuthenticated] - - def get(self, request, guild_id, format=None): - servers = RconServer.get_guild_servers(guild_id) - page = self.paginate_queryset(servers) - if page: - return create_success_response(page, status.HTTP_200_OK, many=True) - return create_success_response(servers, status.HTTP_200_OK, many=True) - - def post(self, request, guild_id, format=None): - data = dict(request.data) - data['guild'] = guild_id - return RconServer.add_new_server(data) - - -class RCONServerDetailAPI(APIView): - permission_classes = [IsAuthenticated] - - def get(self, request, guild_id, name, format=None): - server = RconServer.get_server(guild_id, name) - if server: - return create_success_response(server, status.HTTP_200_OK, many=False) - else: - return create_error_response("RCON Server Does Not Exist", - status=status.HTTP_404_NOT_FOUND) - - def put(self, request, guild_id, name, format=None): - data = dict(request.data) - server = RconServer.get_server(guild_id, name) - if server: - return server.update_server(data) - else: - return create_error_response('RCON Server Does Not Exist', - status=status.HTTP_404_NOT_FOUND) - - -class ListPlayers(PaginatedAPIView): - permission_classes = [IsAuthenticated] - - def get(self, request, guild_id, name, format=None): - server: RconServer = RconServer.get_server(guild_id, name) - if server: - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) - loop = asyncio.get_event_loop() - ark = arcon.ARKServer(host=server.ip, port=server.port, password=server.password, loop=loop) - connected = loop.run_until_complete(ark.connect()) - if connected == 1: - resp = loop.run_until_complete(ark.listplayers()) - if resp == 'No Players Connected': - return create_rcon_response(resp, status=status.HTTP_204_NO_CONTENT) - else: - return create_rcon_response(resp, status=status.HTTP_200_OK) - else: - return create_error_response('Connection failure', - status=status.HTTP_500_INTERNAL_SERVER_ERROR) - - return create_error_response('RCON Server Does Not Exist', - status=status.HTTP_404_NOT_FOUND) diff --git a/geeksbot_v2/shared_libs/TicTacToe/__init__.py b/geeksbot_v2/shared_libs/TicTacToe/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/geeksbot_v2/shared_libs/TicTacToe/board.py b/geeksbot_v2/shared_libs/TicTacToe/board.py deleted file mode 100644 index 35365c6..0000000 --- a/geeksbot_v2/shared_libs/TicTacToe/board.py +++ /dev/null @@ -1,74 +0,0 @@ -from src.shared_libs.guid import Guid -from src.shared_libs.TicTacToe.player import Player - - -class Board: - def __init__(self): - self.id = Guid() - self.board = [[' ', ' ', ' '], - [' ', ' ', ' '], - [' ', ' ', ' ']] - self.history = [] - self.winner = False - self.draw = False - self.play_count = 0 - self.remaining_moves = [1, 2, 3, 4, 5, 6, 7, 8, 9] - self.winning_states = [[(0, 0), (0, 1), (0, 2)], - [(0, 0), (1, 1), (2, 2)], - [(1, 0), (1, 1), (1, 2)], - [(2, 0), (2, 1), (2, 2)], - [(0, 0), (1, 0), (2, 0)], - [(0, 1), (1, 1), (2, 1)], - [(0, 2), (1, 2), (2, 2)], - [(2, 0), (1, 1), (0, 2)]] - - def __repr__(self): - return f'' - - def __str__(self): - return '┌───┬───┬───┐\n' \ - '│ {0[0][0]} │ {0[0][1]} │ {0[0][2]} │\n' \ - '├───┼───┼───┤\n' \ - '│ {0[1][0]} │ {0[1][1]} │ {0[1][2]} │\n' \ - '├───┼───┼───┤\n' \ - '│ {0[2][0]} │ {0[2][1]} │ {0[2][2]} │\n' \ - '└───┴───┴───┘\n'.format(self.board) - - def make_play(self, player: Player, position: int): - assert 1 <= position <= 9 - assert isinstance(player, Player) - move = ((position - 1) // 3, (position - 1) % 3) - if not self.board[move[0]][move[1]] == ' ': - raise Warning("That cell is already taken. Please try again.") - self.history.append(self.board) - self.board[move[0]][move[1]] = player - self.play_count += 1 - self.winner = self.check_winner() - self.draw = self.check_draw() - self.remaining_moves.remove(position) - - def check_winner(self): - for state in self.winning_states: - if (self.board[state[0][0]][state[0][1]] == - self.board[state[1][0]][state[1][1]] == - self.board[state[2][0]][state[2][1]]) and \ - self.board[state[0][0]][state[0][1]] != ' ': - return self.board[state[0][0]][state[0][1]] - return False - - def check_draw(self): - for row in self.board: - for cell in row: - if cell == ' ': - return False - else: - return True - - def clear(self): - self.board = [[' ', ' ', ' '], - [' ', ' ', ' '], - [' ', ' ', ' ']] - self.history = [] - self.winner = False - self.play_count = 0 - diff --git a/geeksbot_v2/shared_libs/TicTacToe/player.py b/geeksbot_v2/shared_libs/TicTacToe/player.py deleted file mode 100644 index e90278b..0000000 --- a/geeksbot_v2/shared_libs/TicTacToe/player.py +++ /dev/null @@ -1,195 +0,0 @@ -from src.shared_libs.guid import Guid -import random -from copy import deepcopy - -__all__ = ['Player', 'AIPlayer'] - - -class Player: - def __init__(self, token: str, *, name: str=None, id: str=None, discord_id: int=None): - if len(token) != 1: - raise Warning('Token must be exactly one character long.') - self.token = token - self.name = name or f'Player {self.token}' - self.id = id or Guid() - self.starting_player = False - self.discord_id = discord_id - - def __repr__(self): - return f'' - - def __str__(self): - return self.token - - def __eq__(self, other): - if isinstance(other, Player) and other.id == self.id: - return True - elif isinstance(other, str): - return self.token == other - - -class AIPlayer(Player): - def __init__(self, token: str=None, name: str=None, human: Player=None, *, id: str=None): - token = token or '🇽' - if human: - if human.token == token and human.token != '🇴': - token = '🇴' - elif human.token == '🇴': - token = '🇽' - super().__init__(token, name=name or f'Robot {token}', id=id) - self._corner_moves = [1, 3, 7, 9] - self._side_moves = [2, 4, 6, 8] - self._center_move = 5 - self.remaining_corners = deepcopy(self._corner_moves) - self.remaining_sides = deepcopy(self._side_moves) - - def make_selection(self, board, last_play: int=None) -> int: - if last_play in self.remaining_corners: - self.remaining_corners.remove(last_play) - elif last_play in self.remaining_sides: - self.remaining_sides.remove(last_play) - - winning_move = self.check_winning_move(board) - if winning_move: - move = winning_move - else: - blocking_move = self.check_blocking_move(board) - if blocking_move: - move = blocking_move - else: - trap_move = self.attempt_trap(board) - if trap_move: - move = trap_move - else: - starting_move = self.starting_strategy(board) - if self.starting_player and starting_move: - move = starting_move - else: - if board.board[1][1] == ' ': - move = 5 - else: - if self.check_corner_trap(board): - move = random.choice(self.remaining_sides) - else: - if self.remaining_corners: - move = random.choice(self.remaining_corners) - else: - move = random.choice(self.remaining_sides) - if move in self.remaining_corners: - self.remaining_corners.remove(move) - elif move in self.remaining_sides: - self.remaining_sides.remove(move) - print(move) - return move - - def starting_strategy(self, board): - move = False - if board.play_count == 0: - move = random.choice(self.remaining_corners) - self.remaining_corners.remove(move) - elif board.play_count == 2: - if (board.board[0][0] == self and ' ' != board.board[2][2] != self) \ - or (board.board[2][2] == self and ' ' != board.board[0][0] != self) \ - or (board.board[2][0] == self and ' ' != board.board[0][2] != self) \ - or (board.board[0][2] == self and ' ' != board.board[2][0] != self): - move = random.choice(self.remaining_corners) - else: - if board.board[0][0] == self: - move = 9 - elif board.board[2][2] == self: - move = 1 - elif board.board[0][2] == self: - move = 7 - elif board.board[2][0] == self: - move = 3 - self.remaining_corners.remove(move) - elif board.play_count == 4 and self.remaining_corners: - move = random.choice(self.remaining_corners) - self.remaining_corners.remove(move) - return move - - - def check_corner_trap(self, board): - if ' ' != board.board[0][0] == board.board[2][2] != self: - return True - elif ' ' != board.board[0][2] == board.board[2][0] != self: - return True - return False - - def check_blocking_move(self, board): - for position in board.winning_states: - if ' ' != board.board[position[0][0]][position[0][1]] == \ - board.board[position[1][0]][position[1][1]] != self \ - and board.board[position[2][0]][position[2][1]] == ' ': - return ((position[2][0] * 3) + position[2][1]) + 1 - elif ' ' != board.board[position[0][0]][position[0][1]] == \ - board.board[position[2][0]][position[2][1]] != self \ - and board.board[position[1][0]][position[1][1]] == ' ': - return ((position[1][0] * 3) + position[1][1]) + 1 - elif ' ' != board.board[position[2][0]][position[2][1]] == \ - board.board[position[1][0]][position[1][1]] != self \ - and board.board[position[0][0]][position[0][1]] == ' ': - return ((position[0][0] * 3) + position[0][1]) + 1 - return False - - def check_winning_move(self, board): - for position in board.winning_states: - if board.board[position[0][0]][position[0][1]] == board.board[position[1][0]][position[1][1]] == self \ - and board.board[position[2][0]][position[2][1]] == ' ': - return ((position[2][0] * 3) + position[2][1]) + 1 - elif board.board[position[0][0]][position[0][1]] == board.board[position[2][0]][position[2][1]] == self \ - and board.board[position[1][0]][position[1][1]] == ' ': - return ((position[1][0] * 3) + position[1][1]) + 1 - elif board.board[position[2][0]][position[2][1]] == board.board[position[1][0]][position[1][1]] == self \ - and board.board[position[0][0]][position[0][1]] == ' ': - return ((position[0][0] * 3) + position[0][1]) + 1 - return False - - def attempt_trap(self, board): - if board.board[1][1] == self: - if board.board[0][0] == self and \ - board.board[0][1] == ' ' and \ - board.board[0][2] == ' ' and \ - board.board[2][0] == ' ': - return 3 - elif board.board[0][0] == self and \ - board.board[1][0] == ' ' and \ - board.board[0][2] == ' ' and \ - board.board[2][0] == ' ': - return 7 - elif board.board[0][2] == self and \ - board.board[0][1] == ' ' and \ - board.board[0][0] == ' ' and \ - board.board[2][2] == ' ': - return 1 - elif board.board[0][2] == self and \ - board.board[1][2] == ' ' and \ - board.board[0][0] == ' ' and \ - board.board[2][2] == ' ': - return 9 - elif board.board[2][0] == self and \ - board.board[0][0] == ' ' and \ - board.board[0][1] == ' ' and \ - board.board[2][2] == ' ': - return 1 - elif board.board[2][0] == self and \ - board.board[2][1] == ' ' and \ - board.board[2][2] == ' ' and \ - board.board[0][0] == ' ': - return 9 - elif board.board[2][2] == self and \ - board.board[2][1] == ' ' and \ - board.board[2][0] == ' ' and \ - board.board[0][2] == ' ': - return 7 - elif board.board[2][2] == self and \ - board.board[1][2] == ' ' and \ - board.board[0][2] == ' ' and \ - board.board[2][0] == ' ': - return 3 - return False - - def reset_game(self): - self.remaining_sides = deepcopy(self._side_moves) - self.remaining_corners = deepcopy(self._corner_moves) - self.starting_player = False diff --git a/geeksbot_v2/shared_libs/__init__.py b/geeksbot_v2/shared_libs/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/geeksbot_v2/static/css/project.css b/geeksbot_v2/static/css/project.css deleted file mode 100644 index f1d543d..0000000 --- a/geeksbot_v2/static/css/project.css +++ /dev/null @@ -1,13 +0,0 @@ -/* These styles are generated from project.scss. */ - -.alert-debug { - color: black; - background-color: white; - border-color: #d6e9c6; -} - -.alert-error { - color: #b94a48; - background-color: #f2dede; - border-color: #eed3d7; -} diff --git a/geeksbot_v2/static/fonts/.gitkeep b/geeksbot_v2/static/fonts/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/geeksbot_v2/static/images/favicons/favicon.ico b/geeksbot_v2/static/images/favicons/favicon.ico deleted file mode 100644 index e1c1dd1..0000000 Binary files a/geeksbot_v2/static/images/favicons/favicon.ico and /dev/null differ diff --git a/geeksbot_v2/static/js/project.js b/geeksbot_v2/static/js/project.js deleted file mode 100644 index d26d23b..0000000 --- a/geeksbot_v2/static/js/project.js +++ /dev/null @@ -1 +0,0 @@ -/* Project specific Javascript goes here. */ diff --git a/geeksbot_v2/static/sass/custom_bootstrap_vars.scss b/geeksbot_v2/static/sass/custom_bootstrap_vars.scss deleted file mode 100644 index e69de29..0000000 diff --git a/geeksbot_v2/static/sass/project.scss b/geeksbot_v2/static/sass/project.scss deleted file mode 100644 index 3c8f261..0000000 --- a/geeksbot_v2/static/sass/project.scss +++ /dev/null @@ -1,37 +0,0 @@ - - - - -// project specific CSS goes here - -//////////////////////////////// - //Variables// -//////////////////////////////// - -// Alert colors - -$white: #fff; -$mint-green: #d6e9c6; -$black: #000; -$pink: #f2dede; -$dark-pink: #eed3d7; -$red: #b94a48; - -//////////////////////////////// - //Alerts// -//////////////////////////////// - -// bootstrap alert CSS, translated to the django-standard levels of -// debug, info, success, warning, error - -.alert-debug { - background-color: $white; - border-color: $mint-green; - color: $black; -} - -.alert-error { - background-color: $pink; - border-color: $dark-pink; - color: $red; -} diff --git a/geeksbot_v2/templates/403.html b/geeksbot_v2/templates/403.html deleted file mode 100644 index 77db8ae..0000000 --- a/geeksbot_v2/templates/403.html +++ /dev/null @@ -1,9 +0,0 @@ -{% extends "base.html" %} - -{% block title %}Forbidden (403){% endblock %} - -{% block content %} -

Forbidden (403)

- -

CSRF verification failed. Request aborted.

-{% endblock content %} diff --git a/geeksbot_v2/templates/404.html b/geeksbot_v2/templates/404.html deleted file mode 100644 index 98327cd..0000000 --- a/geeksbot_v2/templates/404.html +++ /dev/null @@ -1,9 +0,0 @@ -{% extends "base.html" %} - -{% block title %}Page not found{% endblock %} - -{% block content %} -

Page not found

- -

This is not the page you were looking for.

-{% endblock content %} diff --git a/geeksbot_v2/templates/500.html b/geeksbot_v2/templates/500.html deleted file mode 100644 index 21df606..0000000 --- a/geeksbot_v2/templates/500.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends "base.html" %} - -{% block title %}Server Error{% endblock %} - -{% block content %} -

Ooops!!! 500

- -

Looks like something went wrong!

- -

We track these errors automatically, but if the problem persists feel free to contact us. In the meantime, try refreshing.

-{% endblock content %} - - diff --git a/geeksbot_v2/templates/account/account_inactive.html b/geeksbot_v2/templates/account/account_inactive.html deleted file mode 100644 index 17c2157..0000000 --- a/geeksbot_v2/templates/account/account_inactive.html +++ /dev/null @@ -1,12 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} - -{% block head_title %}{% trans "Account Inactive" %}{% endblock %} - -{% block inner %} -

{% trans "Account Inactive" %}

- -

{% trans "This account is inactive." %}

-{% endblock %} - diff --git a/geeksbot_v2/templates/account/base.html b/geeksbot_v2/templates/account/base.html deleted file mode 100644 index 8e1f260..0000000 --- a/geeksbot_v2/templates/account/base.html +++ /dev/null @@ -1,10 +0,0 @@ -{% extends "base.html" %} -{% block title %}{% block head_title %}{% endblock head_title %}{% endblock title %} - -{% block content %} -
-
- {% block inner %}{% endblock %} -
-
-{% endblock %} diff --git a/geeksbot_v2/templates/account/email.html b/geeksbot_v2/templates/account/email.html deleted file mode 100644 index 0dc8d14..0000000 --- a/geeksbot_v2/templates/account/email.html +++ /dev/null @@ -1,80 +0,0 @@ - -{% extends "account/base.html" %} - -{% load i18n %} -{% load crispy_forms_tags %} - -{% block head_title %}{% trans "Account" %}{% endblock %} - -{% block inner %} -

{% trans "E-mail Addresses" %}

- -{% if user.emailaddress_set.all %} -

{% trans 'The following e-mail addresses are associated with your account:' %}

- - - -{% else %} -

{% trans 'Warning:'%} {% 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." %}

- -{% endif %} - - -

{% trans "Add E-mail Address" %}

- -
- {% csrf_token %} - {{ form|crispy }} - -
- -{% endblock %} - - -{% block javascript %} -{{ block.super }} - -{% endblock %} - diff --git a/geeksbot_v2/templates/account/email_confirm.html b/geeksbot_v2/templates/account/email_confirm.html deleted file mode 100644 index 46c7812..0000000 --- a/geeksbot_v2/templates/account/email_confirm.html +++ /dev/null @@ -1,32 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load account %} - -{% block head_title %}{% trans "Confirm E-mail Address" %}{% endblock %} - - -{% block inner %} -

{% trans "Confirm E-mail Address" %}

- -{% if confirmation %} - -{% user_display confirmation.email_address.user as user_display %} - -

{% blocktrans with confirmation.email_address.email as email %}Please confirm that {{ email }} is an e-mail address for user {{ user_display }}.{% endblocktrans %}

- -
-{% csrf_token %} - -
- -{% else %} - -{% url 'account_email' as email_url %} - -

{% blocktrans %}This e-mail confirmation link expired or is invalid. Please issue a new e-mail confirmation request.{% endblocktrans %}

- -{% endif %} - -{% endblock %} - diff --git a/geeksbot_v2/templates/account/login.html b/geeksbot_v2/templates/account/login.html deleted file mode 100644 index 2cadea6..0000000 --- a/geeksbot_v2/templates/account/login.html +++ /dev/null @@ -1,48 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load account socialaccount %} -{% load crispy_forms_tags %} - -{% block head_title %}{% trans "Sign In" %}{% endblock %} - -{% block inner %} - -

{% trans "Sign In" %}

- -{% get_providers as socialaccount_providers %} - -{% if socialaccount_providers %} -

{% blocktrans with site.name as site_name %}Please sign in with one -of your existing third party accounts. Or, sign up -for a {{ site_name }} account and sign in below:{% endblocktrans %}

- -
- -
    - {% include "socialaccount/snippets/provider_list.html" with process="login" %} -
- - - -
- -{% include "socialaccount/snippets/login_extra.html" %} - -{% else %} -

{% blocktrans %}If you have not created an account yet, then please -sign up first.{% endblocktrans %}

-{% endif %} - - - -{% endblock %} - diff --git a/geeksbot_v2/templates/account/logout.html b/geeksbot_v2/templates/account/logout.html deleted file mode 100644 index 8e2e675..0000000 --- a/geeksbot_v2/templates/account/logout.html +++ /dev/null @@ -1,22 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} - -{% block head_title %}{% trans "Sign Out" %}{% endblock %} - -{% block inner %} -

{% trans "Sign Out" %}

- -

{% trans 'Are you sure you want to sign out?' %}

- -
- {% csrf_token %} - {% if redirect_field_value %} - - {% endif %} - -
- - -{% endblock %} - diff --git a/geeksbot_v2/templates/account/password_change.html b/geeksbot_v2/templates/account/password_change.html deleted file mode 100644 index b72ca06..0000000 --- a/geeksbot_v2/templates/account/password_change.html +++ /dev/null @@ -1,17 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load crispy_forms_tags %} - -{% block head_title %}{% trans "Change Password" %}{% endblock %} - -{% block inner %} -

{% trans "Change Password" %}

- -
- {% csrf_token %} - {{ form|crispy }} - -
-{% endblock %} - diff --git a/geeksbot_v2/templates/account/password_reset.html b/geeksbot_v2/templates/account/password_reset.html deleted file mode 100644 index 845bbda..0000000 --- a/geeksbot_v2/templates/account/password_reset.html +++ /dev/null @@ -1,26 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load account %} -{% load crispy_forms_tags %} - -{% block head_title %}{% trans "Password Reset" %}{% endblock %} - -{% block inner %} - -

{% trans "Password Reset" %}

- {% if user.is_authenticated %} - {% include "account/snippets/already_logged_in.html" %} - {% endif %} - -

{% trans "Forgotten your password? Enter your e-mail address below, and we'll send you an e-mail allowing you to reset it." %}

- -
- {% csrf_token %} - {{ form|crispy }} - -
- -

{% blocktrans %}Please contact us if you have any trouble resetting your password.{% endblocktrans %}

-{% endblock %} - diff --git a/geeksbot_v2/templates/account/password_reset_done.html b/geeksbot_v2/templates/account/password_reset_done.html deleted file mode 100644 index c59534a..0000000 --- a/geeksbot_v2/templates/account/password_reset_done.html +++ /dev/null @@ -1,17 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load account %} - -{% block head_title %}{% trans "Password Reset" %}{% endblock %} - -{% block inner %} -

{% trans "Password Reset" %}

- - {% if user.is_authenticated %} - {% include "account/snippets/already_logged_in.html" %} - {% endif %} - -

{% blocktrans %}We have sent you an e-mail. Please contact us if you do not receive it within a few minutes.{% endblocktrans %}

-{% endblock %} - diff --git a/geeksbot_v2/templates/account/password_reset_from_key.html b/geeksbot_v2/templates/account/password_reset_from_key.html deleted file mode 100644 index 4abdb56..0000000 --- a/geeksbot_v2/templates/account/password_reset_from_key.html +++ /dev/null @@ -1,25 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load crispy_forms_tags %} -{% block head_title %}{% trans "Change Password" %}{% endblock %} - -{% block inner %} -

{% if token_fail %}{% trans "Bad Token" %}{% else %}{% trans "Change Password" %}{% endif %}

- - {% if token_fail %} - {% url 'account_reset_password' as passwd_reset_url %} -

{% blocktrans %}The password reset link was invalid, possibly because it has already been used. Please request a new password reset.{% endblocktrans %}

- {% else %} - {% if form %} -
- {% csrf_token %} - {{ form|crispy }} - -
- {% else %} -

{% trans 'Your password is now changed.' %}

- {% endif %} - {% endif %} -{% endblock %} - diff --git a/geeksbot_v2/templates/account/password_reset_from_key_done.html b/geeksbot_v2/templates/account/password_reset_from_key_done.html deleted file mode 100644 index 89be086..0000000 --- a/geeksbot_v2/templates/account/password_reset_from_key_done.html +++ /dev/null @@ -1,10 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% block head_title %}{% trans "Change Password" %}{% endblock %} - -{% block inner %} -

{% trans "Change Password" %}

-

{% trans 'Your password is now changed.' %}

-{% endblock %} - diff --git a/geeksbot_v2/templates/account/password_set.html b/geeksbot_v2/templates/account/password_set.html deleted file mode 100644 index 2232223..0000000 --- a/geeksbot_v2/templates/account/password_set.html +++ /dev/null @@ -1,17 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load crispy_forms_tags %} - -{% block head_title %}{% trans "Set Password" %}{% endblock %} - -{% block inner %} -

{% trans "Set Password" %}

- -
- {% csrf_token %} - {{ form|crispy }} - -
-{% endblock %} - diff --git a/geeksbot_v2/templates/account/signup.html b/geeksbot_v2/templates/account/signup.html deleted file mode 100644 index 6a2954e..0000000 --- a/geeksbot_v2/templates/account/signup.html +++ /dev/null @@ -1,23 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load crispy_forms_tags %} - -{% block head_title %}{% trans "Signup" %}{% endblock %} - -{% block inner %} -

{% trans "Sign Up" %}

- -

{% blocktrans %}Already have an account? Then please sign in.{% endblocktrans %}

- - - -{% endblock %} - diff --git a/geeksbot_v2/templates/account/signup_closed.html b/geeksbot_v2/templates/account/signup_closed.html deleted file mode 100644 index 2322f17..0000000 --- a/geeksbot_v2/templates/account/signup_closed.html +++ /dev/null @@ -1,12 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} - -{% block head_title %}{% trans "Sign Up Closed" %}{% endblock %} - -{% block inner %} -

{% trans "Sign Up Closed" %}

- -

{% trans "We are sorry, but the sign up is currently closed." %}

-{% endblock %} - diff --git a/geeksbot_v2/templates/account/verification_sent.html b/geeksbot_v2/templates/account/verification_sent.html deleted file mode 100644 index ad093fd..0000000 --- a/geeksbot_v2/templates/account/verification_sent.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} - -{% block head_title %}{% trans "Verify Your E-mail Address" %}{% endblock %} - -{% block inner %} -

{% trans "Verify Your E-mail Address" %}

- -

{% 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 %}

- -{% endblock %} - diff --git a/geeksbot_v2/templates/account/verified_email_required.html b/geeksbot_v2/templates/account/verified_email_required.html deleted file mode 100644 index 09d4fde..0000000 --- a/geeksbot_v2/templates/account/verified_email_required.html +++ /dev/null @@ -1,24 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} - -{% block head_title %}{% trans "Verify Your E-mail Address" %}{% endblock %} - -{% block inner %} -

{% trans "Verify Your E-mail Address" %}

- -{% url 'account_email' as email_url %} - -

{% blocktrans %}This part of the site requires us to verify that -you are who you claim to be. For this purpose, we require that you -verify ownership of your e-mail address. {% endblocktrans %}

- -

{% blocktrans %}We have sent an e-mail to you for -verification. Please click on the link inside this e-mail. Please -contact us if you do not receive it within a few minutes.{% endblocktrans %}

- -

{% blocktrans %}Note: you can still change your e-mail address.{% endblocktrans %}

- - -{% endblock %} - diff --git a/geeksbot_v2/templates/base.html b/geeksbot_v2/templates/base.html deleted file mode 100644 index 547b0c1..0000000 --- a/geeksbot_v2/templates/base.html +++ /dev/null @@ -1,110 +0,0 @@ -{% load static i18n %} - - - - - {% block title %}geeksbot{% endblock title %} - - - - - - - - - - {% block css %} - - - - - - - - - - - - - {% endblock %} - - - - - -
- - -
- -
- - {% if messages %} - {% for message in messages %} -
{{ message }}
- {% endfor %} - {% endif %} - - {% block content %} -

Use this document as a way to quick start any new project.

- {% endblock content %} - -
- - {% block modal %}{% endblock modal %} - - - - {% block javascript %} - - - - - - - - - - - - - - - {% endblock javascript %} - - - diff --git a/geeksbot_v2/templates/pages/about.html b/geeksbot_v2/templates/pages/about.html deleted file mode 100644 index 63913c1..0000000 --- a/geeksbot_v2/templates/pages/about.html +++ /dev/null @@ -1 +0,0 @@ -{% extends "base.html" %} \ No newline at end of file diff --git a/geeksbot_v2/templates/pages/home.html b/geeksbot_v2/templates/pages/home.html deleted file mode 100644 index 63913c1..0000000 --- a/geeksbot_v2/templates/pages/home.html +++ /dev/null @@ -1 +0,0 @@ -{% extends "base.html" %} \ No newline at end of file diff --git a/geeksbot_v2/templates/users/user_detail.html b/geeksbot_v2/templates/users/user_detail.html deleted file mode 100644 index c8c5d13..0000000 --- a/geeksbot_v2/templates/users/user_detail.html +++ /dev/null @@ -1,37 +0,0 @@ -{% extends "base.html" %} -{% load static %} - -{% block title %}User: {{ object.username }}{% endblock %} - -{% block content %} -
- -
-
- -

{{ object.username }}

- {% if object.name %} -

{{ object.name }}

- {% endif %} - {{ user.auth_token }} -
-
- -{% if object == request.user %} - -
- -
- My Info - E-Mail - -
- -
- -{% endif %} - - -
-{% endblock content %} - diff --git a/geeksbot_v2/templates/users/user_form.html b/geeksbot_v2/templates/users/user_form.html deleted file mode 100644 index a054047..0000000 --- a/geeksbot_v2/templates/users/user_form.html +++ /dev/null @@ -1,17 +0,0 @@ -{% extends "base.html" %} -{% load crispy_forms_tags %} - -{% block title %}{{ user.username }}{% endblock %} - -{% block content %} -

{{ user.username }}

-
- {% csrf_token %} - {{ form|crispy }} -
-
- -
-
-
-{% endblock %} diff --git a/geeksbot_v2/users/__init__.py b/geeksbot_v2/users/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/geeksbot_v2/users/adapters.py b/geeksbot_v2/users/adapters.py deleted file mode 100644 index 41ee20e..0000000 --- a/geeksbot_v2/users/adapters.py +++ /dev/null @@ -1,35 +0,0 @@ -from typing import Any - -from allauth.account.adapter import DefaultAccountAdapter -from allauth.socialaccount.adapter import DefaultSocialAccountAdapter -from allauth.account.utils import user_email, user_username, user_field -from allauth.utils import valid_email_or_none -from django.conf import settings -from django.http import HttpRequest - - -class AccountAdapter(DefaultAccountAdapter): - def is_open_for_signup(self, request: HttpRequest): - return getattr(settings, "ACCOUNT_ALLOW_REGISTRATION", False) - - -class SocialAccountAdapter(DefaultSocialAccountAdapter): - def is_open_for_signup(self, request: HttpRequest, sociallogin: Any): - return getattr(settings, "SOCIAL_ACCOUNT_ALLOW_REGISTRATION", True) - - def populate_user(self, request, sociallogin, data): -# print(sociallogin.account.extra_data) - first_name = data.get('first_name') - last_name = data.get('last_name') - name = data.get('name') - id = sociallogin.account.extra_data.get('id') - user = sociallogin.user - user_username(user, data.get('username', '')) - user_email(user, valid_email_or_none(data.get('email')) or '') - name_parts = (name or '').partition(' ') - user_field(user, 'first_name', first_name or name_parts[0]) - user_field(user, 'last_name', last_name or name_parts[2]) - user_field(user, 'id', id or '') - user_field(user, 'avatar', sociallogin.account.extra_data.get('avatar', '')) - user_field(user, 'discriminator', sociallogin.account.extra_data.get('discriminator', '')) - return user diff --git a/geeksbot_v2/users/admin.py b/geeksbot_v2/users/admin.py deleted file mode 100644 index c3af8e4..0000000 --- a/geeksbot_v2/users/admin.py +++ /dev/null @@ -1,17 +0,0 @@ -from django.contrib import admin -from django.contrib.auth import admin as auth_admin - -from .forms import UserChangeForm, UserCreateForm -from .models import User - - -class UserAdmin(auth_admin.UserAdmin): - model = User - form = UserChangeForm - add_form = UserCreateForm - add_fieldsets = auth_admin.UserAdmin.add_fieldsets + ( - (None, {'fields': ('id')}), - ) - - -admin.site.register(User, UserAdmin) diff --git a/geeksbot_v2/users/api_urls.py b/geeksbot_v2/users/api_urls.py deleted file mode 100644 index 7047da4..0000000 --- a/geeksbot_v2/users/api_urls.py +++ /dev/null @@ -1,11 +0,0 @@ -from django.urls import path - -from geeksbot_v2.users.views import UsersAPI, UserDetail, UserLogList, UserLogDetail - -app_name = "users_api" -urlpatterns = [ - path("", view=UsersAPI.as_view(), name="list"), - path("/", view=UserDetail.as_view(), name="detail"), - path("/logs/", view=UserLogList.as_view(), name="log_list"), - path("/logs/", view=UserLogDetail.as_view(), name="log_detail"), -] diff --git a/geeksbot_v2/users/apps.py b/geeksbot_v2/users/apps.py deleted file mode 100644 index 8982bd2..0000000 --- a/geeksbot_v2/users/apps.py +++ /dev/null @@ -1,13 +0,0 @@ -from django.apps import AppConfig -from django.utils.translation import gettext_lazy as _ - - -class UsersConfig(AppConfig): - name = "geeksbot_v2.users" - verbose_name = _("Users") - - def ready(self): - try: - import geeksbot_v2.users.signals # noqa F401 - except ImportError: - pass diff --git a/geeksbot_v2/users/forms.py b/geeksbot_v2/users/forms.py deleted file mode 100644 index 74227a8..0000000 --- a/geeksbot_v2/users/forms.py +++ /dev/null @@ -1,20 +0,0 @@ -from django.contrib.auth import forms -from django.forms import CharField -from allauth.account.forms import SignupForm - -from .models import User - - -class UserCreateForm(SignupForm): - id = CharField(max_length=30, label='Discord ID') - - def save(self, request): - user = super(UserCreateForm, self).save(request) - user.id = self.cleaned_data['id'] - user.save() - return user - - -class UserChangeForm(forms.UserChangeForm): - class Meta(forms.UserChangeForm.Meta): - model = User diff --git a/geeksbot_v2/users/migrations/0001_initial.py b/geeksbot_v2/users/migrations/0001_initial.py deleted file mode 100644 index 5b7996a..0000000 --- a/geeksbot_v2/users/migrations/0001_initial.py +++ /dev/null @@ -1,70 +0,0 @@ -# Generated by Django 2.2.4 on 2019-09-20 21:39 - -from django.conf import settings -import django.contrib.auth.models -import django.contrib.auth.validators -import django.contrib.postgres.fields -from django.db import migrations, models -import django.db.models.deletion -import django.utils.timezone - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('auth', '0011_update_proxy_permissions'), - ('guilds', '0001_initial'), - ] - - operations = [ - migrations.CreateModel( - name='User', - fields=[ - ('password', models.CharField(max_length=128, verbose_name='password')), - ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), - ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), - ('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')), - ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), - ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), - ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), - ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), - ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), - ('name', models.CharField(blank=True, max_length=255, verbose_name='Name of User')), - ('username', models.CharField(help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), - ('id', models.CharField(max_length=30, primary_key=True, serialize=False)), - ('discord_username', models.CharField(max_length=100, null=True)), - ('previous_discord_usernames', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=100), blank=True, null=True, size=None)), - ('discriminator', models.CharField(max_length=4, null=True)), - ('previous_discriminators', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=4), blank=True, null=True, size=None)), - ('steam_id', models.CharField(blank=True, max_length=30, null=True)), - ('animated', models.BooleanField(blank=True, null=True)), - ('avatar', models.CharField(blank=True, max_length=100, null=True)), - ('bot', models.BooleanField(blank=True, null=True)), - ('banned', models.BooleanField(default=False)), - ('logging_enabled', models.BooleanField(default=True)), - ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), - ('guilds', models.ManyToManyField(blank=True, null=True, to='guilds.Guild')), - ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), - ], - options={ - 'verbose_name': 'user', - 'verbose_name_plural': 'users', - 'abstract': False, - }, - managers=[ - ('objects', django.contrib.auth.models.UserManager()), - ], - ), - migrations.CreateModel( - name='UserLog', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('time', models.DateTimeField(auto_now_add=True)), - ('action', models.IntegerField()), - ('description', models.CharField(blank=True, max_length=100, null=True)), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), - ], - ), - ] diff --git a/geeksbot_v2/users/migrations/__init__.py b/geeksbot_v2/users/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/geeksbot_v2/users/models.py b/geeksbot_v2/users/models.py deleted file mode 100644 index 2eb7e62..0000000 --- a/geeksbot_v2/users/models.py +++ /dev/null @@ -1,207 +0,0 @@ -from django.contrib.auth.models import AbstractUser -from django.contrib.auth.validators import UnicodeUsernameValidator -from django.db.models import CharField -from django.urls import reverse -from django.utils.translation import ugettext_lazy as _ -from django.db import models -from django.contrib.postgres.fields import ArrayField -from django.conf import settings -from django.db.models.signals import post_save -from django.dispatch import receiver -from rest_framework.authtoken.models import Token -from django.core.exceptions import ObjectDoesNotExist -from rest_framework import status - -from geeksbot_v2.guilds.models import Guild -from .utils import verify_user_data -from .utils import create_error_response -from .utils import create_log_success_response -from .utils import create_success_response - - -@receiver(post_save, sender=settings.AUTH_USER_MODEL) -def create_auth_token(sender, instance=None, created=False, **kwargs): - if created: - Token.objects.create(user=instance) - - -class User(AbstractUser): - - # First Name and Last Name do not cover name patterns - # around the globe. - name = CharField(_("Name of User"), blank=True, max_length=255) - username = models.CharField( - _('username'), - max_length=150, - unique=False, - help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'), - validators=[UnicodeUsernameValidator()], - ) - id = models.CharField(max_length=30, primary_key=True) - discord_username = models.CharField(max_length=100, null=True) - previous_discord_usernames = ArrayField(models.CharField(max_length=100), blank=True, null=True) - discriminator = models.CharField(max_length=4, null=True) - previous_discriminators = ArrayField(models.CharField(max_length=4), blank=True, null=True) - guilds = models.ManyToManyField(Guild, blank=True, null=True) - steam_id = models.CharField(max_length=30, blank=True, null=True) - animated = models.BooleanField(blank=True, null=True) - avatar = models.CharField(max_length=100, blank=True, null=True) - bot = models.BooleanField(blank=True, null=True) - banned = models.BooleanField(default=False) - logging_enabled = models.BooleanField(default=True) - - @classmethod - def add_new_user(cls, data): - if not verify_user_data(data): - return create_error_response("Not all required fields are present.", - status=status.HTTP_400_BAD_REQUEST) - id = data.get('id') - if id: - if User.objects.filter(id=id).exists(): - return create_error_response("User Exists please update instead of create", - status=status.HTTP_409_CONFLICT) - discord_username = data.get('username') - discriminator = data.get('discriminator') - guild_id = data.get('guild') - try: - guild = Guild.objects.get(id=str(guild_id)) - except ObjectDoesNotExist: - return create_error_response("That is not a valid Guild", - status=status.HTTP_400_BAD_REQUEST) - animated = data.get('animated') - avatar = data.get('avatar') - bot = data.get('bot') - banned = data.get('banned') - logging = data.get('logging') - if not (avatar and (animated is not None) and (bot is not None)): - return create_error_response("All required fields must contain a value", - status.HTTP_400_BAD_REQUEST) - - user = User( - id=id, - discord_username=discord_username, - discriminator=discriminator, - animated=animated, - avatar=avatar, - bot=bot, - banned=banned or False, - logging_enabled=logging or True - ) - user.save() - user.guilds.add(guild) - return create_success_response(user, status.HTTP_201_CREATED, many=False) - - def update_user(self, data): - if data.get('username') and data.get('username') != self.discord_username: - if isinstance(self.previous_discord_usernames, list): - self.previous_discord_usernames.append(self.discord_username) - else: - self.previous_discord_usernames = [self.discord_username, ] - self.discord_username = data.get('username') - if data.get('discriminator') and data.get('discriminator') != self.discriminator: - if isinstance(self.previous_discriminators, list): - self.previous_discriminators.append(self.discriminator) - else: - self.previous_discriminators = [self.discriminator, ] - self.discriminator = data.get('discriminator') - if data.get('guild'): - guild = Guild.get_guild_by_id(data.get('guild')) - if not isinstance(guild, Guild): - return create_error_response("That is not a valid Guild", - status=status.HTTP_400_BAD_REQUEST) - self.guilds.add(guild) - if data.get('steam_id'): - self.steam_id = data.get('steam_id') - if data.get('animated'): - self.animated = data.get('animated') - if data.get('avatar'): - self.avatar = data.get('avatar') - if data.get('bot'): - self.bot = data.get('bot') - if data.get('banned'): - self.banned = data.get('banned') - if data.get('logging'): - self.logging_enabled = data.get('logging') - - self.save() - return create_success_response(self, status.HTTP_202_ACCEPTED, many=False) - - @classmethod - def get_user_by_id(cls, id): - try: - return cls.objects.get(id=id) - except ObjectDoesNotExist: - return None - - def get_absolute_url(self): - return reverse("users:detail", kwargs={"username": self.username}) - - -class UserLog(models.Model): - user = models.ForeignKey(User, on_delete=models.CASCADE) - time = models.DateTimeField(auto_now_add=True, blank=True) - action = models.IntegerField() - description = models.CharField(max_length=100, null=True, blank=True) - - @classmethod - def add_new_log(cls, user, data): - user_id = data.get('user') - action = data.get('action') - description = data.get('description') - if not (user_id and action): - return create_error_response("User and Action are required.", - status=status.HTTP_400_BAD_REQUEST) - user = User.get_user_by_id(user_id) - if not isinstance(user, User): - return create_error_response("User Does Not Exist", - status=status.HTTP_404_NOT_FOUND) - try: - action = int(action) - except ValueError: - return create_error_response("The Action must be a number", - status=status.HTTP_400_BAD_REQUEST) - log = cls( - user=user, - action=action, - description=description - ) - log.save() - return create_log_success_response(log, status.HTTP_201_CREATED, many=False) - - @classmethod - def get_log_by_id(cls, id): - try: - return cls.objects.get(id=id) - except ObjectDoesNotExist: - return None - - @classmethod - def get_logs_by_user(cls, user_id, count: int = None): - user = User.get_user_by_id(user_id) - if isinstance(user, User): - user_logs = cls.objects.filter(user=user).order_by('-time') - if count: - user_logs = user_logs[:count] - if len(user_logs) > 0: - return user_logs - else: - return [] - else: - return [] - - @classmethod - def get_logs_by_user_action(cls, user_id, action, count: int = None): - user = User.get_user_by_id(user_id) - if isinstance(user, User): - user_logs = cls.objects.filter(user=user, action=action).order_by('-time') - if count: - user_logs = user_logs[:count] - if len(user_logs) > 0: - return user_logs - else: - return [] - else: - return [] - - def __str__(self): - return f"{self.time} | {self.user.id} | {self.action}" diff --git a/geeksbot_v2/users/serializers.py b/geeksbot_v2/users/serializers.py deleted file mode 100644 index a989d4a..0000000 --- a/geeksbot_v2/users/serializers.py +++ /dev/null @@ -1,57 +0,0 @@ -from rest_framework import serializers - -from geeksbot_v2.users.models import User -from geeksbot_v2.users.models import UserLog - - -class UserSerializer(serializers.HyperlinkedModelSerializer): - class Meta: - model = User - fields = [ - 'id', - 'username', - 'name', - 'discord_username', - 'previous_discord_usernames', - 'discriminator', - 'previous_discriminators', - 'guilds', - 'steam_id', - 'animated', - 'avatar', - 'bot', - 'banned', - 'logging_enabled', - 'is_staff', - 'is_superuser', - 'url' - ] - extra_kwargs = { - 'url': { - 'view_name': 'users_api:detail', - 'lookup_field': 'id' - }, - 'guilds': { - 'view_name': 'guilds_api:detail', - 'lookup_field': 'id' - } - } - - -class UserLogSerializer(serializers.ModelSerializer): - class Meta: - model = UserLog - fields = [ - 'user', - 'time', - 'action', - 'description', - 'url' - ] - extra_fields = { - 'url': { - 'view_name': 'users_api:log_detail', - 'lookup_field': 'id', - 'lookup_url_kwarg': 'log' - } - } diff --git a/geeksbot_v2/users/tests/__init__.py b/geeksbot_v2/users/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/geeksbot_v2/users/tests/factories.py b/geeksbot_v2/users/tests/factories.py deleted file mode 100644 index b537136..0000000 --- a/geeksbot_v2/users/tests/factories.py +++ /dev/null @@ -1,27 +0,0 @@ -from typing import Any, Sequence - -from django.contrib.auth import get_user_model -from factory import DjangoModelFactory, Faker, post_generation - - -class UserFactory(DjangoModelFactory): - - username = Faker("user_name") - email = Faker("email") - name = Faker("name") - - @post_generation - def password(self, create: bool, extracted: Sequence[Any], **kwargs): - password = Faker( - "password", - length=42, - special_chars=True, - digits=True, - upper_case=True, - lower_case=True, - ).generate(extra_kwargs={}) - self.set_password(password) - - class Meta: - model = get_user_model() - django_get_or_create = ["username"] diff --git a/geeksbot_v2/users/tests/test_forms.py b/geeksbot_v2/users/tests/test_forms.py deleted file mode 100644 index 820a77c..0000000 --- a/geeksbot_v2/users/tests/test_forms.py +++ /dev/null @@ -1,40 +0,0 @@ -import pytest - -from geeksbot_v2.users.forms import UserCreationForm -from geeksbot_v2.users.tests.factories import UserFactory - -pytestmark = pytest.mark.django_db - - -class TestUserCreationForm: - def test_clean_username(self): - # A user with proto_user params does not exist yet. - proto_user = UserFactory.build() - - form = UserCreationForm( - { - "username": proto_user.username, - "password1": proto_user._password, - "password2": proto_user._password, - } - ) - - assert form.is_valid() - assert form.clean_username() == proto_user.username - - # Creating a user. - form.save() - - # The user with proto_user params already exists, - # hence cannot be created. - form = UserCreationForm( - { - "username": proto_user.username, - "password1": proto_user._password, - "password2": proto_user._password, - } - ) - - assert not form.is_valid() - assert len(form.errors) == 1 - assert "username" in form.errors diff --git a/geeksbot_v2/users/tests/test_models.py b/geeksbot_v2/users/tests/test_models.py deleted file mode 100644 index 5486363..0000000 --- a/geeksbot_v2/users/tests/test_models.py +++ /dev/null @@ -1,8 +0,0 @@ -import pytest -from django.conf import settings - -pytestmark = pytest.mark.django_db - - -def test_user_get_absolute_url(user: settings.AUTH_USER_MODEL): - assert user.get_absolute_url() == f"/users/{user.username}/" diff --git a/geeksbot_v2/users/tests/test_urls.py b/geeksbot_v2/users/tests/test_urls.py deleted file mode 100644 index c636192..0000000 --- a/geeksbot_v2/users/tests/test_urls.py +++ /dev/null @@ -1,23 +0,0 @@ -import pytest -from django.conf import settings -from django.urls import reverse, resolve - -pytestmark = pytest.mark.django_db - - -def test_detail(user: settings.AUTH_USER_MODEL): - assert ( - reverse("users:detail", kwargs={"username": user.username}) - == f"/users/{user.username}/" - ) - assert resolve(f"/users/{user.username}/").view_name == "users:detail" - - -def test_update(): - assert reverse("users:update") == "/users/~update/" - assert resolve("/users/~update/").view_name == "users:update" - - -def test_redirect(): - assert reverse("users:redirect") == "/users/~redirect/" - assert resolve("/users/~redirect/").view_name == "users:redirect" diff --git a/geeksbot_v2/users/tests/test_views.py b/geeksbot_v2/users/tests/test_views.py deleted file mode 100644 index 221b0d3..0000000 --- a/geeksbot_v2/users/tests/test_views.py +++ /dev/null @@ -1,52 +0,0 @@ -import pytest -from django.conf import settings -from django.test import RequestFactory - -from geeksbot_v2.users.views import UserRedirectView, UserUpdateView - -pytestmark = pytest.mark.django_db - - -class TestUserUpdateView: - """ - TODO: - extracting view initialization code as class-scoped fixture - would be great if only pytest-django supported non-function-scoped - fixture db access -- this is a work-in-progress for now: - https://github.com/pytest-dev/pytest-django/pull/258 - """ - - def test_get_success_url( - self, user: settings.AUTH_USER_MODEL, request_factory: RequestFactory - ): - view = UserUpdateView() - request = request_factory.get("/fake-url/") - request.user = user - - view.request = request - - assert view.get_success_url() == f"/users/{user.username}/" - - def test_get_object( - self, user: settings.AUTH_USER_MODEL, request_factory: RequestFactory - ): - view = UserUpdateView() - request = request_factory.get("/fake-url/") - request.user = user - - view.request = request - - assert view.get_object() == user - - -class TestUserRedirectView: - def test_get_redirect_url( - self, user: settings.AUTH_USER_MODEL, request_factory: RequestFactory - ): - view = UserRedirectView() - request = request_factory.get("/fake-url") - request.user = user - - view.request = request - - assert view.get_redirect_url() == f"/users/{user.username}/" diff --git a/geeksbot_v2/users/urls.py b/geeksbot_v2/users/urls.py deleted file mode 100644 index 3d733d2..0000000 --- a/geeksbot_v2/users/urls.py +++ /dev/null @@ -1,14 +0,0 @@ -from django.urls import path - -from geeksbot_v2.users.views import ( - user_redirect_view, - user_update_view, - user_detail_view, -) - -app_name = "users" -urlpatterns = [ - path("~redirect/", view=user_redirect_view, name="redirect"), - path("~update/", view=user_update_view, name="update"), - path("/", view=user_detail_view, name="detail"), -] diff --git a/geeksbot_v2/users/utils.py b/geeksbot_v2/users/utils.py deleted file mode 100644 index 393d9bd..0000000 --- a/geeksbot_v2/users/utils.py +++ /dev/null @@ -1,36 +0,0 @@ -from rest_framework.response import Response -from rest_framework import status - - -def create_error_response(msg, status=status.HTTP_404_NOT_FOUND): - return Response({'details': msg}, - status=status) - - -def create_success_response(user_data, status, many: bool = False): - from .serializers import UserSerializer - - return Response(UserSerializer(user_data, many=many).data, - status=status) - - -def create_log_success_response(log_data, status, many: bool = False): - from .serializers import UserLogSerializer - - return Response(UserLogSerializer(log_data, many=many).data, - status=status) - - -required_fields = [ - 'id', - 'username', - 'discriminator', - 'guild', - 'animated', - 'avatar', - 'bot', -] - - -def verify_user_data(data): - return all([field in data.keys() for field in required_fields]) diff --git a/geeksbot_v2/users/views.py b/geeksbot_v2/users/views.py deleted file mode 100644 index 8569169..0000000 --- a/geeksbot_v2/users/views.py +++ /dev/null @@ -1,163 +0,0 @@ -from django.contrib.auth.mixins import LoginRequiredMixin -from django.urls import reverse -from django.views.generic import DetailView, RedirectView, UpdateView -from django.contrib import messages -from django.utils.translation import ugettext_lazy as _ -from rest_framework.views import APIView -from rest_framework import generics -from rest_framework.permissions import IsAuthenticated -from rest_framework import status - - -from .models import UserLog -from geeksbot_v2.utils.api_utils import PaginatedAPIView -from .models import User -from .serializers import UserSerializer -from .serializers import UserLogSerializer -from geeksbot_v2.utils.permissions import CustomDjangoModelPermissions -from geeksbot_v2.utils.permissions import CustomDjangoObjectPermissions -from .utils import create_error_response -from .utils import create_success_response -from .utils import create_log_success_response - - -class UserDetailView(LoginRequiredMixin, DetailView): - - model = User - slug_field = "username" - slug_url_kwarg = "username" - - def get(self, request, *args, **kwargs): - self.object = self.get_object() - - context = self.get_context_data(object=self.object, user=request.user) - return self.render_to_response(context) - - -user_detail_view = UserDetailView.as_view() - - -class UserUpdateView(LoginRequiredMixin, UpdateView): - - model = User - fields = ["name"] - - def get_success_url(self): - return reverse("users:detail", kwargs={"username": self.request.user.username}) - - def get_object(self): - return User.objects.get(username=self.request.user.username) - - def form_valid(self, form): - messages.add_message( - self.request, messages.INFO, _("Infos successfully updated") - ) - return super().form_valid(form) - - -user_update_view = UserUpdateView.as_view() - - -class UserRedirectView(LoginRequiredMixin, RedirectView): - - permanent = False - - def get_redirect_url(self): - return reverse("users:detail", kwargs={"username": self.request.user.username}) - - -user_redirect_view = UserRedirectView.as_view() - -# API Views - - -class UsersAPI(generics.ListCreateAPIView): - permission_classes = [IsAuthenticated] - serializer_class = UserSerializer - - def get_queryset(self): - return User.objects.filter(guilds__id=self.request.data.get('guild')) - - # def get(self, request, guild=None, format=None): - # if guild: - # users = User.objects.filter(guilds__id=guild) - # else: - # users = User.objects.all() - # page = self.paginate_queryset(users) - # if page is not None: - # return create_success_response(page, status.HTTP_200_OK, many=True) - # - # return create_success_response(users, status.HTTP_200_OK, many=True) - # - # def post(self, request, format=None): - # data = dict(request.data) - # return User.add_new_user(data) - - -class UserDetail(generics.RetrieveUpdateDestroyAPIView): - permission_classes = [IsAuthenticated] - serializer_class = UserSerializer - lookup_field = 'id' - - def get_queryset(self): - return User.objects.all() - - # def get(self, request, id, format=None): - # user = User.get_user_by_id(id) - # if not isinstance(user, User): - # return create_error_response("User Does not Exist", - # status=status.HTTP_404_NOT_FOUND) - # return create_success_response(user, - # status=status.HTTP_200_OK) - # - # def put(self, request, id, format=None): - # user = User.get_user_by_id(id) - # if isinstance(user, User): - # data = dict(request.data) - # return user.update_user(data) - # else: - # return create_error_response("User Does Not Exist", - # status=status.HTTP_404_NOT_FOUND) - - -class UserLogList(generics.ListCreateAPIView): - permission_classes = [IsAuthenticated] - serializer_class = UserLogSerializer - - def get_queryset(self): - return UserLog.objects.all() - - # def get(self, request, user, action=None, format=None): - # if action: - # user_logs = UserLog.get_logs_by_user_action(user, action) - # else: - # user_logs = UserLog.get_logs_by_user(user) - # - # page = self.paginate_queryset(user_logs) - # if page is not None: - # return create_log_success_response(page, status.HTTP_200_OK, many=True) - # - # return create_log_success_response(user_logs, status.HTTP_200_OK, many=True) - # - # def post(self, request, user, format=None): - # data = dict(request.data) - # return UserLog.add_new_log(user, data) - - -class UserLogDetail(generics.RetrieveUpdateAPIView): - permission_classes = [IsAuthenticated] - serializer_class = UserLogSerializer - lookup_url_kwarg = 'log' - lookup_field = 'id' - - def get_queryset(self): - user_id = self.kwargs['id'] - return UserLog.objects.filter(user__id=user_id) - - # def get(self, request, id, format=None): - # user_log = UserLog.get_log_by_id(id) - # if isinstance(user_log, UserLog): - # return create_log_success_response(user_log, status.HTTP_200_OK, many=False) - # else: - # return create_error_response("Log Does Not Exist", - # status=status.HTTP_404_NOT_FOUND) diff --git a/geeksbot_v2/utils/api_utils.py b/geeksbot_v2/utils/api_utils.py deleted file mode 100644 index 62a1775..0000000 --- a/geeksbot_v2/utils/api_utils.py +++ /dev/null @@ -1,33 +0,0 @@ -from rest_framework.views import APIView -from rest_framework.settings import api_settings - - -class PaginatedAPIView(APIView): - pagination_class = api_settings.DEFAULT_PAGINATION_CLASS - - @property - def paginator(self): - """ - The paginator instance associated with the view, or `None`. - """ - if not hasattr(self, "_paginator"): - if self.pagination_class is None: - self._paginator = None - else: - self._paginator = self.pagination_class() - return self._paginator - - def paginate_queryset(self, queryset): - """ - Return a single page of results, or `None` if pagination is disabled. - """ - if self.paginator is None: - return None - return self.paginator.paginate_queryset(queryset, self.request, view=self) - - def get_paginated_response(self, data): - """ - Return a paginated style `Response` object for the given output data. - """ - assert self.paginator is not None - return self.paginator.get_paginated_response(data) diff --git a/geeksbot_v2/utils/permissions.py b/geeksbot_v2/utils/permissions.py deleted file mode 100644 index fb55609..0000000 --- a/geeksbot_v2/utils/permissions.py +++ /dev/null @@ -1,27 +0,0 @@ -from rest_framework.permissions import DjangoModelPermissions, DjangoObjectPermissions - - -class CustomDjangoModelPermissions(DjangoModelPermissions): - # Overriding to require view permissions - perms_map = { - 'GET': ['%(app_label)s.view_%(model_name)s'], - 'OPTIONS': ['%(app_label)s.view_%(model_name)s'], - 'HEAD': ['%(app_label)s.view_%(model_name)s'], - 'POST': ['%(app_label)s.add_%(model_name)s'], - 'PUT': ['%(app_label)s.change_%(model_name)s'], - 'PATCH': ['%(app_label)s.change_%(model_name)s'], - 'DELETE': ['%(app_label)s.delete_%(model_name)s'], - } - - -class CustomDjangoObjectPermissions(DjangoObjectPermissions): - # Overriding to require view permissions - perms_map = { - 'GET': ['%(app_label)s.view_%(model_name)s'], - 'OPTIONS': ['%(app_label)s.view_%(model_name)s'], - 'HEAD': ['%(app_label)s.view_%(model_name)s'], - 'POST': ['%(app_label)s.add_%(model_name)s'], - 'PUT': ['%(app_label)s.change_%(model_name)s'], - 'PATCH': ['%(app_label)s.change_%(model_name)s'], - 'DELETE': ['%(app_label)s.delete_%(model_name)s'], - } diff --git a/local.yml b/local.yml deleted file mode 100644 index a9f2865..0000000 --- a/local.yml +++ /dev/null @@ -1,33 +0,0 @@ -version: '3' - -volumes: - local_postgres_data: {} - local_postgres_data_backups: {} - -services: - django: - build: - context: . - dockerfile: ./compose/local/django/Dockerfile - image: geeksbot_v2_local_django - depends_on: - - postgres - volumes: - - .:/app - env_file: - - ./.envs/.local/.django - - ./.envs/.local/.postgres - ports: - - "8000:8000" - command: /start - - postgres: - build: - context: . - dockerfile: ./compose/production/postgres/Dockerfile - image: geeksbot_v2_production_postgres - volumes: - - local_postgres_data:/var/lib/postgresql/data - - local_postgres_data_backups:/backups - env_file: - - ./.envs/.local/.postgres diff --git a/locale/README.rst b/locale/README.rst deleted file mode 100644 index c2f1dcd..0000000 --- a/locale/README.rst +++ /dev/null @@ -1,6 +0,0 @@ -Translations -============ - -Translations will be placed in this folder when running:: - - python manage.py makemessages diff --git a/merge_production_dotenvs_in_dotenv.py b/merge_production_dotenvs_in_dotenv.py deleted file mode 100644 index 4e70e2a..0000000 --- a/merge_production_dotenvs_in_dotenv.py +++ /dev/null @@ -1,66 +0,0 @@ -import os -from typing import Sequence - -import pytest - -ROOT_DIR_PATH = os.path.dirname(os.path.realpath(__file__)) -PRODUCTION_DOTENVS_DIR_PATH = os.path.join(ROOT_DIR_PATH, ".envs", ".production") -PRODUCTION_DOTENV_FILE_PATHS = [ - os.path.join(PRODUCTION_DOTENVS_DIR_PATH, ".django"), - os.path.join(PRODUCTION_DOTENVS_DIR_PATH, ".postgres"), -] -DOTENV_FILE_PATH = os.path.join(ROOT_DIR_PATH, ".env") - - -def merge( - output_file_path: str, merged_file_paths: Sequence[str], append_linesep: bool = True -) -> None: - with open(output_file_path, "w") as output_file: - for merged_file_path in merged_file_paths: - with open(merged_file_path, "r") as merged_file: - merged_file_content = merged_file.read() - output_file.write(merged_file_content) - if append_linesep: - output_file.write(os.linesep) - - -def main(): - merge(DOTENV_FILE_PATH, PRODUCTION_DOTENV_FILE_PATHS) - - -@pytest.mark.parametrize("merged_file_count", range(3)) -@pytest.mark.parametrize("append_linesep", [True, False]) -def test_merge(tmpdir_factory, merged_file_count: int, append_linesep: bool): - tmp_dir_path = str(tmpdir_factory.getbasetemp()) - - output_file_path = os.path.join(tmp_dir_path, ".env") - - expected_output_file_content = "" - merged_file_paths = [] - for i in range(merged_file_count): - merged_file_ord = i + 1 - - merged_filename = ".service{}".format(merged_file_ord) - merged_file_path = os.path.join(tmp_dir_path, merged_filename) - - merged_file_content = merged_filename * merged_file_ord - - with open(merged_file_path, "w+") as file: - file.write(merged_file_content) - - expected_output_file_content += merged_file_content - if append_linesep: - expected_output_file_content += os.linesep - - merged_file_paths.append(merged_file_path) - - merge(output_file_path, merged_file_paths, append_linesep) - - with open(output_file_path, "r") as output_file: - actual_output_file_content = output_file.read() - - assert actual_output_file_content == expected_output_file_content - - -if __name__ == "__main__": - main() diff --git a/production.yml b/production.yml deleted file mode 100644 index 27b97ad..0000000 --- a/production.yml +++ /dev/null @@ -1,55 +0,0 @@ -version: '3' - -volumes: - production_postgres_data: {} - production_postgres_data_backups: {} - production_traefik: {} - -services: - django: - build: - context: . - dockerfile: ./compose/production/django/Dockerfile - image: geeksbot_v2_production_django - depends_on: - - postgres - - redis - env_file: - - ./.envs/.production/.django - - ./.envs/.production/.postgres - command: /start - - postgres: - build: - context: . - dockerfile: ./compose/production/postgres/Dockerfile - image: geeksbot_v2_production_postgres - volumes: - - production_postgres_data:/var/lib/postgresql/data - - production_postgres_data_backups:/backups - env_file: - - ./.envs/.production/.postgres - - traefik: - build: - context: . - dockerfile: ./compose/production/traefik/Dockerfile - image: geeksbot_v2_production_traefik - depends_on: - - django - volumes: - - production_traefik:/etc/traefik/acme - ports: - - "0.0.0.0:80:80" - - "0.0.0.0:443:443" - - redis: - image: redis:5.0 - awscli: - build: - context: . - dockerfile: ./compose/production/aws/Dockerfile - env_file: - - ./.envs/.production/.django - volumes: - - production_postgres_data_backups:/backups diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index ec08413..0000000 --- a/pytest.ini +++ /dev/null @@ -1,2 +0,0 @@ -[pytest] -addopts = --ds=config.settings.test diff --git a/requirements/local.txt b/requirements/local.txt index 953bca3..dfe358b 100644 --- a/requirements/local.txt +++ b/requirements/local.txt @@ -1,5 +1,7 @@ -r ./base.txt +docker-compose + Werkzeug==0.14.1 # pyup: < 0.15 # https://github.com/pallets/werkzeug ipdb==0.12.2 # https://github.com/gotcha/ipdb Sphinx==2.2.0 # https://github.com/sphinx-doc/sphinx diff --git a/requirements/web.txt b/requirements/web.txt deleted file mode 100644 index 8298e9d..0000000 --- a/requirements/web.txt +++ /dev/null @@ -1,22 +0,0 @@ -# Django -# ------------------------------------------------------------------------------ -django==2.2.4 # pyup: < 3.0 # https://www.djangoproject.com/ -django-environ==0.4.5 # https://github.com/joke2k/django-environ -django-model-utils==3.2.0 # https://github.com/jazzband/django-model-utils -django-allauth==0.39.1 # https://github.com/pennersr/django-allauth -django-crispy-forms==1.7.2 # https://github.com/django-crispy-forms/django-crispy-forms -django-redis==4.10.0 # https://github.com/niwinz/django-redis -django-anymail[mailgun]==6.1.0 # https://github.com/anymail/django-anymail -django-debug-toolbar -django-extensions - -# Django REST Framework -djangorestframework==3.10.2 # https://github.com/encode/django-rest-framework -coreapi==2.3.3 # https://github.com/core-api/python-client - -gevent -gunicorn==19.9.0 # https://github.com/benoitc/gunicorn -psycopg2==2.8.3 --no-binary psycopg2 # https://github.com/psycopg/psycopg2 -Collectfast==1.0.0 # https://github.com/antonagestam/collectfast - -python-valve diff --git a/services/Dockerfile-geeksbot b/services/Dockerfile-geeksbot deleted file mode 100644 index 9592c30..0000000 --- a/services/Dockerfile-geeksbot +++ /dev/null @@ -1,12 +0,0 @@ -FROM geeksbot-base AS geeksbot - -WORKDIR /code - -COPY requirements/base.txt . -COPY requirements/production.txt . -COPY requirements/geeksbot.txt . - -RUN pip install -r production.txt -RUN pip install -r geeksbot.txt - -CMD ["python", "-m", "geeksbot"] diff --git a/services/Dockerfile-web b/services/Dockerfile-web deleted file mode 100644 index 45fc2e1..0000000 --- a/services/Dockerfile-web +++ /dev/null @@ -1,37 +0,0 @@ -FROM geeksbot-base AS geeksbot-web - -WORKDIR /code - -RUN apk update && apk add nginx && apk add supervisor - -COPY requirements/base.txt . -COPY requirements/production.txt . -COPY requirements/web.txt . - -RUN pip install -r production.txt -RUN pip install -r web.txt - -RUN rm -f /etc/nginx/sites-enabled/default -RUN rm -f /etc/nginx/conf.d/default.conf -COPY ./services/web/nginx.conf /etc/nginx/nginx.conf -COPY ./services/web/geeksbot.conf /etc/nginx/sites-enabled/geeksbot -COPY ./services/web/gunicorn.conf /etc/gunicorn.conf -COPY ./services/web/supervisord.conf /etc/supervisor/supervisord.conf -COPY ./services/web/supervisor_geeksbot.conf /etc/supervisor/conf.d/geeksbot.conf -COPY ./ssl_certs/geeksbot_app/geeksbot_app_cert_chain.crt /etc/ssl/geeksbot_app_cert_chain.crt -COPY ./ssl_certs/geeksbot_app/geeksbot.app.key /etc/ssl/geeksbot.app.key -COPY ./.env /code/ - -RUN rm -rf /tmp/* - -RUN mkdir -p /tmp/logs/nginx -RUN mkdir -p /tmp/logs/geeksbot - -WORKDIR /code/geeksbot_v2 - -# RUN sed -i 's/\r$//g' ./entrypoint -# RUN chmod +x ./entrypoint - -EXPOSE 80 8000 443 - -ENTRYPOINT [ "./entrypoint" ] diff --git a/services/postgresql/postgres.conf b/services/postgresql/postgres.conf deleted file mode 100644 index 44c7a46..0000000 --- a/services/postgresql/postgres.conf +++ /dev/null @@ -1,690 +0,0 @@ -# ----------------------------- -# PostgreSQL configuration file -# ----------------------------- -# -# This file consists of lines of the form: -# -# name = value -# -# (The "=" is optional.) Whitespace may be used. Comments are introduced with -# "#" anywhere on a line. The complete list of parameter names and allowed -# values can be found in the PostgreSQL documentation. -# -# The commented-out settings shown in this file represent the default values. -# Re-commenting a setting is NOT sufficient to revert it to the default value; -# you need to reload the server. -# -# This file is read on server startup and when the server receives a SIGHUP -# signal. If you edit the file on a running system, you have to SIGHUP the -# server for the changes to take effect, run "pg_ctl reload", or execute -# "SELECT pg_reload_conf()". Some parameters, which are marked below, -# require a server shutdown and restart to take effect. -# -# Any parameter can also be given as a command-line option to the server, e.g., -# "postgres -c log_connections=on". Some parameters can be changed at run time -# with the "SET" SQL command. -# -# Memory units: kB = kilobytes Time units: ms = milliseconds -# MB = megabytes s = seconds -# GB = gigabytes min = minutes -# TB = terabytes h = hours -# d = days - - -#------------------------------------------------------------------------------ -# FILE LOCATIONS -#------------------------------------------------------------------------------ - -# The default values of these variables are driven from the -D command-line -# option or PGDATA environment variable, represented here as ConfigDir. - -#data_directory = 'ConfigDir' # use data in another directory - # (change requires restart) -#hba_file = 'ConfigDir/pg_hba.conf' # host-based authentication file - # (change requires restart) -#ident_file = 'ConfigDir/pg_ident.conf' # ident configuration file - # (change requires restart) - -# If external_pid_file is not explicitly set, no extra PID file is written. -#external_pid_file = '' # write an extra PID file - # (change requires restart) - - -#------------------------------------------------------------------------------ -# CONNECTIONS AND AUTHENTICATION -#------------------------------------------------------------------------------ - -# - Connection Settings - - -listen_addresses = '*' - # comma-separated list of addresses; - # defaults to 'localhost'; use '*' for all - # (change requires restart) -#port = 5432 # (change requires restart) -max_connections = 1000 # (change requires restart) -#superuser_reserved_connections = 3 # (change requires restart) -#unix_socket_directories = '/tmp' # comma-separated list of directories - # (change requires restart) -#unix_socket_group = '' # (change requires restart) -#unix_socket_permissions = 0777 # begin with 0 to use octal notation - # (change requires restart) -#bonjour = off # advertise server via Bonjour - # (change requires restart) -#bonjour_name = '' # defaults to the computer name - # (change requires restart) - -# - TCP Keepalives - -# see "man 7 tcp" for details - -#tcp_keepalives_idle = 0 # TCP_KEEPIDLE, in seconds; - # 0 selects the system default -#tcp_keepalives_interval = 0 # TCP_KEEPINTVL, in seconds; - # 0 selects the system default -#tcp_keepalives_count = 0 # TCP_KEEPCNT; - # 0 selects the system default - -# - Authentication - - -#authentication_timeout = 1min # 1s-600s -#password_encryption = md5 # md5 or scram-sha-256 -#db_user_namespace = off - -# GSSAPI using Kerberos -#krb_server_keyfile = '' -#krb_caseins_users = off - -# - SSL - - -#ssl = off -#ssl_ca_file = '' -#ssl_cert_file = 'server.crt' -#ssl_crl_file = '' -#ssl_key_file = 'server.key' -#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers -#ssl_prefer_server_ciphers = on -#ssl_ecdh_curve = 'prime256v1' -#ssl_dh_params_file = '' -#ssl_passphrase_command = '' -#ssl_passphrase_command_supports_reload = off - - -#------------------------------------------------------------------------------ -# RESOURCE USAGE (except WAL) -#------------------------------------------------------------------------------ - -# - Memory - - -#shared_buffers = 32MB # min 128kB - # (change requires restart) -#huge_pages = try # on, off, or try - # (change requires restart) -#temp_buffers = 8MB # min 800kB -#max_prepared_transactions = 0 # zero disables the feature - # (change requires restart) -# Caution: it is not advisable to set max_prepared_transactions nonzero unless -# you actively intend to use prepared transactions. -#work_mem = 4MB # min 64kB -#maintenance_work_mem = 64MB # min 1MB -#autovacuum_work_mem = -1 # min 1MB, or -1 to use maintenance_work_mem -#max_stack_depth = 2MB # min 100kB -#dynamic_shared_memory_type = posix # the default is the first option - # supported by the operating system: - # posix - # sysv - # windows - # mmap - # use none to disable dynamic shared memory - # (change requires restart) - -# - Disk - - -#temp_file_limit = -1 # limits per-process temp file space - # in kB, or -1 for no limit - -# - Kernel Resources - - -#max_files_per_process = 1000 # min 25 - # (change requires restart) - -# - Cost-Based Vacuum Delay - - -#vacuum_cost_delay = 0 # 0-100 milliseconds -#vacuum_cost_page_hit = 1 # 0-10000 credits -#vacuum_cost_page_miss = 10 # 0-10000 credits -#vacuum_cost_page_dirty = 20 # 0-10000 credits -#vacuum_cost_limit = 200 # 1-10000 credits - -# - Background Writer - - -#bgwriter_delay = 200ms # 10-10000ms between rounds -#bgwriter_lru_maxpages = 100 # max buffers written/round, 0 disables -#bgwriter_lru_multiplier = 2.0 # 0-10.0 multiplier on buffers scanned/round -#bgwriter_flush_after = 0 # measured in pages, 0 disables - -# - Asynchronous Behavior - - -#effective_io_concurrency = 1 # 1-1000; 0 disables prefetching -#max_worker_processes = 8 # (change requires restart) -#max_parallel_maintenance_workers = 2 # taken from max_parallel_workers -#max_parallel_workers_per_gather = 2 # taken from max_parallel_workers -#parallel_leader_participation = on -#max_parallel_workers = 8 # maximum number of max_worker_processes that - # can be used in parallel operations -#old_snapshot_threshold = -1 # 1min-60d; -1 disables; 0 is immediate - # (change requires restart) -#backend_flush_after = 0 # measured in pages, 0 disables - - -#------------------------------------------------------------------------------ -# WRITE-AHEAD LOG -#------------------------------------------------------------------------------ - -# - Settings - - -#wal_level = replica # minimal, replica, or logical - # (change requires restart) -#fsync = on # flush data to disk for crash safety - # (turning this off can cause - # unrecoverable data corruption) -#synchronous_commit = on # synchronization level; - # off, local, remote_write, remote_apply, or on -#wal_sync_method = fsync # the default is the first option - # supported by the operating system: - # open_datasync - # fdatasync (default on Linux) - # fsync - # fsync_writethrough - # open_sync -#full_page_writes = on # recover from partial page writes -#wal_compression = off # enable compression of full-page writes -#wal_log_hints = off # also do full page writes of non-critical updates - # (change requires restart) -#wal_buffers = -1 # min 32kB, -1 sets based on shared_buffers - # (change requires restart) -#wal_writer_delay = 200ms # 1-10000 milliseconds -#wal_writer_flush_after = 1MB # measured in pages, 0 disables - -#commit_delay = 0 # range 0-100000, in microseconds -#commit_siblings = 5 # range 1-1000 - -# - Checkpoints - - -#checkpoint_timeout = 5min # range 30s-1d -#max_wal_size = 1GB -#min_wal_size = 80MB -#checkpoint_completion_target = 0.5 # checkpoint target duration, 0.0 - 1.0 -#checkpoint_flush_after = 0 # measured in pages, 0 disables -#checkpoint_warning = 30s # 0 disables - -# - Archiving - - -#archive_mode = off # enables archiving; off, on, or always - # (change requires restart) -#archive_command = '' # command to use to archive a logfile segment - # placeholders: %p = path of file to archive - # %f = file name only - # e.g. 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f' -#archive_timeout = 0 # force a logfile segment switch after this - # number of seconds; 0 disables - - -#------------------------------------------------------------------------------ -# REPLICATION -#------------------------------------------------------------------------------ - -# - Sending Servers - - -# Set these on the master and on any standby that will send replication data. - -#max_wal_senders = 10 # max number of walsender processes - # (change requires restart) -#wal_keep_segments = 0 # in logfile segments; 0 disables -#wal_sender_timeout = 60s # in milliseconds; 0 disables - -#max_replication_slots = 10 # max number of replication slots - # (change requires restart) -#track_commit_timestamp = off # collect timestamp of transaction commit - # (change requires restart) - -# - Master Server - - -# These settings are ignored on a standby server. - -#synchronous_standby_names = '' # standby servers that provide sync rep - # method to choose sync standbys, number of sync standbys, - # and comma-separated list of application_name - # from standby(s); '*' = all -#vacuum_defer_cleanup_age = 0 # number of xacts by which cleanup is delayed - -# - Standby Servers - - -# These settings are ignored on a master server. - -#hot_standby = on # "off" disallows queries during recovery - # (change requires restart) -#max_standby_archive_delay = 30s # max delay before canceling queries - # when reading WAL from archive; - # -1 allows indefinite delay -#max_standby_streaming_delay = 30s # max delay before canceling queries - # when reading streaming WAL; - # -1 allows indefinite delay -#wal_receiver_status_interval = 10s # send replies at least this often - # 0 disables -#hot_standby_feedback = off # send info from standby to prevent - # query conflicts -#wal_receiver_timeout = 60s # time that receiver waits for - # communication from master - # in milliseconds; 0 disables -#wal_retrieve_retry_interval = 5s # time to wait before retrying to - # retrieve WAL after a failed attempt - -# - Subscribers - - -# These settings are ignored on a publisher. - -#max_logical_replication_workers = 4 # taken from max_worker_processes - # (change requires restart) -#max_sync_workers_per_subscription = 2 # taken from max_logical_replication_workers - - -#------------------------------------------------------------------------------ -# QUERY TUNING -#------------------------------------------------------------------------------ - -# - Planner Method Configuration - - -#enable_bitmapscan = on -#enable_hashagg = on -#enable_hashjoin = on -#enable_indexscan = on -#enable_indexonlyscan = on -#enable_material = on -#enable_mergejoin = on -#enable_nestloop = on -#enable_parallel_append = on -#enable_seqscan = on -#enable_sort = on -#enable_tidscan = on -#enable_partitionwise_join = off -#enable_partitionwise_aggregate = off -#enable_parallel_hash = on -#enable_partition_pruning = on - -# - Planner Cost Constants - - -#seq_page_cost = 1.0 # measured on an arbitrary scale -#random_page_cost = 4.0 # same scale as above -#cpu_tuple_cost = 0.01 # same scale as above -#cpu_index_tuple_cost = 0.005 # same scale as above -#cpu_operator_cost = 0.0025 # same scale as above -#parallel_tuple_cost = 0.1 # same scale as above -#parallel_setup_cost = 1000.0 # same scale as above - -#jit_above_cost = 100000 # perform JIT compilation if available - # and query more expensive than this; - # -1 disables -#jit_inline_above_cost = 500000 # inline small functions if query is - # more expensive than this; -1 disables -#jit_optimize_above_cost = 500000 # use expensive JIT optimizations if - # query is more expensive than this; - # -1 disables - -#min_parallel_table_scan_size = 8MB -#min_parallel_index_scan_size = 512kB -#effective_cache_size = 4GB - -# - Genetic Query Optimizer - - -#geqo = on -#geqo_threshold = 12 -#geqo_effort = 5 # range 1-10 -#geqo_pool_size = 0 # selects default based on effort -#geqo_generations = 0 # selects default based on effort -#geqo_selection_bias = 2.0 # range 1.5-2.0 -#geqo_seed = 0.0 # range 0.0-1.0 - -# - Other Planner Options - - -#default_statistics_target = 100 # range 1-10000 -#constraint_exclusion = partition # on, off, or partition -#cursor_tuple_fraction = 0.1 # range 0.0-1.0 -#from_collapse_limit = 8 -#join_collapse_limit = 8 # 1 disables collapsing of explicit - # JOIN clauses -#force_parallel_mode = off -#jit = off # allow JIT compilation - - -#------------------------------------------------------------------------------ -# REPORTING AND LOGGING -#------------------------------------------------------------------------------ - -# - Where to Log - - -#log_destination = 'stderr' # Valid values are combinations of - # stderr, csvlog, syslog, and eventlog, - # depending on platform. csvlog - # requires logging_collector to be on. - -# This is used when logging to stderr: -#logging_collector = off # Enable capturing of stderr and csvlog - # into log files. Required to be on for - # csvlogs. - # (change requires restart) - -# These are only used if logging_collector is on: -#log_directory = 'log' # directory where log files are written, - # can be absolute or relative to PGDATA -#log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' # log file name pattern, - # can include strftime() escapes -#log_file_mode = 0600 # creation mode for log files, - # begin with 0 to use octal notation -#log_truncate_on_rotation = off # If on, an existing log file with the - # same name as the new log file will be - # truncated rather than appended to. - # But such truncation only occurs on - # time-driven rotation, not on restarts - # or size-driven rotation. Default is - # off, meaning append to existing files - # in all cases. -#log_rotation_age = 1d # Automatic rotation of logfiles will - # happen after that time. 0 disables. -#log_rotation_size = 10MB # Automatic rotation of logfiles will - # happen after that much log output. - # 0 disables. - -# These are relevant when logging to syslog: -#syslog_facility = 'LOCAL0' -#syslog_ident = 'postgres' -#syslog_sequence_numbers = on -#syslog_split_messages = on - -# This is only relevant when logging to eventlog (win32): -# (change requires restart) -#event_source = 'PostgreSQL' - -# - When to Log - - -#log_min_messages = warning # values in order of decreasing detail: - # debug5 - # debug4 - # debug3 - # debug2 - # debug1 - # info - # notice - # warning - # error - # log - # fatal - # panic - -#log_min_error_statement = error # values in order of decreasing detail: - # debug5 - # debug4 - # debug3 - # debug2 - # debug1 - # info - # notice - # warning - # error - # log - # fatal - # panic (effectively off) - -#log_min_duration_statement = -1 # -1 is disabled, 0 logs all statements - # and their durations, > 0 logs only - # statements running at least this number - # of milliseconds - - -# - What to Log - - -#debug_print_parse = off -#debug_print_rewritten = off -#debug_print_plan = off -#debug_pretty_print = on -#log_checkpoints = off -#log_connections = off -#log_disconnections = off -#log_duration = off -#log_error_verbosity = default # terse, default, or verbose messages -#log_hostname = off -#log_line_prefix = '%m [%p] ' # special values: - # %a = application name - # %u = user name - # %d = database name - # %r = remote host and port - # %h = remote host - # %p = process ID - # %t = timestamp without milliseconds - # %m = timestamp with milliseconds - # %n = timestamp with milliseconds (as a Unix epoch) - # %i = command tag - # %e = SQL state - # %c = session ID - # %l = session line number - # %s = session start timestamp - # %v = virtual transaction ID - # %x = transaction ID (0 if none) - # %q = stop here in non-session - # processes - # %% = '%' - # e.g. '<%u%%%d> ' -#log_lock_waits = off # log lock waits >= deadlock_timeout -#log_statement = 'none' # none, ddl, mod, all -#log_replication_commands = off -#log_temp_files = -1 # log temporary files equal or larger - # than the specified size in kilobytes; - # -1 disables, 0 logs all temp files -#log_timezone = 'GMT' - -#------------------------------------------------------------------------------ -# PROCESS TITLE -#------------------------------------------------------------------------------ - -#cluster_name = '' # added to process titles if nonempty - # (change requires restart) -#update_process_title = on - - -#------------------------------------------------------------------------------ -# STATISTICS -#------------------------------------------------------------------------------ - -# - Query and Index Statistics Collector - - -#track_activities = on -#track_counts = on -#track_io_timing = off -#track_functions = none # none, pl, all -#track_activity_query_size = 1024 # (change requires restart) -#stats_temp_directory = 'pg_stat_tmp' - - -# - Monitoring - - -#log_parser_stats = off -#log_planner_stats = off -#log_executor_stats = off -#log_statement_stats = off - - -#------------------------------------------------------------------------------ -# AUTOVACUUM -#------------------------------------------------------------------------------ - -#autovacuum = on # Enable autovacuum subprocess? 'on' - # requires track_counts to also be on. -#log_autovacuum_min_duration = -1 # -1 disables, 0 logs all actions and - # their durations, > 0 logs only - # actions running at least this number - # of milliseconds. -#autovacuum_max_workers = 3 # max number of autovacuum subprocesses - # (change requires restart) -#autovacuum_naptime = 1min # time between autovacuum runs -#autovacuum_vacuum_threshold = 50 # min number of row updates before - # vacuum -#autovacuum_analyze_threshold = 50 # min number of row updates before - # analyze -#autovacuum_vacuum_scale_factor = 0.2 # fraction of table size before vacuum -#autovacuum_analyze_scale_factor = 0.1 # fraction of table size before analyze -#autovacuum_freeze_max_age = 200000000 # maximum XID age before forced vacuum - # (change requires restart) -#autovacuum_multixact_freeze_max_age = 400000000 # maximum multixact age - # before forced vacuum - # (change requires restart) -#autovacuum_vacuum_cost_delay = 20ms # default vacuum cost delay for - # autovacuum, in milliseconds; - # -1 means use vacuum_cost_delay -#autovacuum_vacuum_cost_limit = -1 # default vacuum cost limit for - # autovacuum, -1 means use - # vacuum_cost_limit - - -#------------------------------------------------------------------------------ -# CLIENT CONNECTION DEFAULTS -#------------------------------------------------------------------------------ - -# - Statement Behavior - - -#client_min_messages = notice # values in order of decreasing detail: - # debug5 - # debug4 - # debug3 - # debug2 - # debug1 - # log - # notice - # warning - # error -#search_path = '"$user", public' # schema names -#row_security = on -#default_tablespace = '' # a tablespace name, '' uses the default -#temp_tablespaces = '' # a list of tablespace names, '' uses - # only default tablespace -#check_function_bodies = on -#default_transaction_isolation = 'read committed' -#default_transaction_read_only = off -#default_transaction_deferrable = off -#session_replication_role = 'origin' -#statement_timeout = 0 # in milliseconds, 0 is disabled -#lock_timeout = 0 # in milliseconds, 0 is disabled -#idle_in_transaction_session_timeout = 0 # in milliseconds, 0 is disabled -#vacuum_freeze_min_age = 50000000 -#vacuum_freeze_table_age = 150000000 -#vacuum_multixact_freeze_min_age = 5000000 -#vacuum_multixact_freeze_table_age = 150000000 -#vacuum_cleanup_index_scale_factor = 0.1 # fraction of total number of tuples - # before index cleanup, 0 always performs - # index cleanup -#bytea_output = 'hex' # hex, escape -#xmlbinary = 'base64' -#xmloption = 'content' -#gin_fuzzy_search_limit = 0 -#gin_pending_list_limit = 4MB - -# - Locale and Formatting - - -#datestyle = 'iso, mdy' -#intervalstyle = 'postgres' -#timezone = 'GMT' -#timezone_abbreviations = 'Default' # Select the set of available time zone - # abbreviations. Currently, there are - # Default - # Australia (historical usage) - # India - # You can create your own file in - # share/timezonesets/. -#extra_float_digits = 0 # min -15, max 3 -#client_encoding = sql_ascii # actually, defaults to database - # encoding - -# These settings are initialized by initdb, but they can be changed. -#lc_messages = 'C' # locale for system error message - # strings -#lc_monetary = 'C' # locale for monetary formatting -#lc_numeric = 'C' # locale for number formatting -#lc_time = 'C' # locale for time formatting - -# default configuration for text search -#default_text_search_config = 'pg_catalog.simple' - -# - Shared Library Preloading - - -#shared_preload_libraries = '' # (change requires restart) -#local_preload_libraries = '' -#session_preload_libraries = '' -#jit_provider = 'llvmjit' # JIT library to use - -# - Other Defaults - - -#dynamic_library_path = '$libdir' - - -#------------------------------------------------------------------------------ -# LOCK MANAGEMENT -#------------------------------------------------------------------------------ - -#deadlock_timeout = 1s -#max_locks_per_transaction = 64 # min 10 - # (change requires restart) -#max_pred_locks_per_transaction = 64 # min 10 - # (change requires restart) -#max_pred_locks_per_relation = -2 # negative values mean - # (max_pred_locks_per_transaction - # / -max_pred_locks_per_relation) - 1 -#max_pred_locks_per_page = 2 # min 0 - - -#------------------------------------------------------------------------------ -# VERSION AND PLATFORM COMPATIBILITY -#------------------------------------------------------------------------------ - -# - Previous PostgreSQL Versions - - -#array_nulls = on -#backslash_quote = safe_encoding # on, off, or safe_encoding -#default_with_oids = off -#escape_string_warning = on -#lo_compat_privileges = off -#operator_precedence_warning = off -#quote_all_identifiers = off -#standard_conforming_strings = on -#synchronize_seqscans = on - -# - Other Platforms and Clients - - -#transform_null_equals = off - - -#------------------------------------------------------------------------------ -# ERROR HANDLING -#------------------------------------------------------------------------------ - -#exit_on_error = off # terminate session on any error? -#restart_after_crash = on # reinitialize after backend crash? -#data_sync_retry = off # retry or panic on failure to fsync - # data? - # (change requires restart) - - -#------------------------------------------------------------------------------ -# CONFIG FILE INCLUDES -#------------------------------------------------------------------------------ - -# These options allow settings to be loaded from files other than the -# default postgresql.conf. - -#include_dir = '' # include files ending in '.conf' from - # a directory, e.g., 'conf.d' -#include_if_exists = '' # include file only if it exists -#include = '' # include file - - -#------------------------------------------------------------------------------ -# CUSTOMIZED OPTIONS -#------------------------------------------------------------------------------ - -# Add settings for extensions here diff --git a/services/web/geeksbot.conf b/services/web/geeksbot.conf deleted file mode 100644 index 1019f13..0000000 --- a/services/web/geeksbot.conf +++ /dev/null @@ -1,48 +0,0 @@ -upstream app_server { - server 127.0.0.1:8000 fail_timeout=0; -} - -server { - listen 443 ssl; - keepalive_timeout 5; - - ssl_certificate /etc/ssl/geeksbot_app_cert_chain.crt; - ssl_certificate_key /etc/ssl/geeksbot.app.key; - - access_log /tmp/logs/geeksbot/access.log; - error_log /tmp/logs/geeksbot/error.log; - - location /static/ { - alias /code/geeksbot_v2/staticfiles/; - } - - location /error/ { - alias /code/geeksbot_v2/staticfiles/errors/; - } - - location / { - try_files $uri @proxy_to_app; - } - - location @proxy_to_app { - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header Host $http_host; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_redirect off; - proxy_buffering off; - proxy_read_timeout 180; - proxy_connect_timeout 180; - - if (!-f $request_filename) { - proxy_pass http://app_server; - break; - } - } - - error_page 500 502 503 504 /error/maintenance.html; -} - -server { - listen 80 default_server; - return 301 https://$host$request_uri; -} \ No newline at end of file diff --git a/services/web/gunicorn.conf b/services/web/gunicorn.conf deleted file mode 100644 index 6636983..0000000 --- a/services/web/gunicorn.conf +++ /dev/null @@ -1,10 +0,0 @@ -import multiprocessing - -bind = "0.0.0.0:8000" -workers = multiprocessing.cpu_count() * 2 + 1 -worker_class = "gevent" -worker_connections = 4096 -timeout = 180 -backlog = 2048 -pidfile = "/tmp/geeksbot.pid" -reload = True \ No newline at end of file diff --git a/services/web/nginx.conf b/services/web/nginx.conf deleted file mode 100644 index 14446ff..0000000 --- a/services/web/nginx.conf +++ /dev/null @@ -1,44 +0,0 @@ -user geeksbot; -master_process off; -# set open fd limit to 30000 -worker_rlimit_nofile 30000; -pid /var/run/nginx.pid; -daemon off; - -events { - worker_connections 4096; - accept_mutex off; -} - -http { - # Basic Settings - sendfile on; - tcp_nopush on; - tcp_nodelay on; - keepalive_timeout 65; - types_hash_max_size 2048; - client_max_body_size 200M; - - include /etc/nginx/mime.types; - default_type application/octet-stream; - - # Logging - access_log /tmp/logs/nginx/access.log; - error_log /tmp/logs/nginx/error.log; - - # Gzip - - gzip on; - gzip_proxied any; - gzip_comp_level 2; - gzip_http_version 1.1; - gzip_buffers 16 8k; - gzip_types text/plain text/css application/json application/x-javascript text/xml applicaion/xml application/xml-rss text/javascript; - gzip_disable "msie6"; - gzip_vary on; - - # Virtual Host Configs - - include /etc/nginx/conf.d/*.conf; - include /etc/nginx/sites-enabled/*; -} \ No newline at end of file diff --git a/services/web/supervisor_geeksbot.conf b/services/web/supervisor_geeksbot.conf deleted file mode 100644 index 9197c4a..0000000 --- a/services/web/supervisor_geeksbot.conf +++ /dev/null @@ -1,15 +0,0 @@ -[program:geeksbot] -command=/usr/local/bin/gunicorn config.wsgi:application -c /etc/gunicorn.conf -directory=/code/geeksbot_v2 -stdout_logfile=/tmp/logs/geeksbot/gunicorn.log -autostart=true -autorestart=true -redirect_stderr=true -user=geeksbot - -[program:nginx] -command=/usr/sbin/nginx -stdout_logfile=/tmp/logs/nginx/access.log -stderr_logfile=/tmp/logs/nginx/error.log -autostart=true -autorestart=true diff --git a/services/web/supervisord.conf b/services/web/supervisord.conf deleted file mode 100644 index 14ce905..0000000 --- a/services/web/supervisord.conf +++ /dev/null @@ -1,21 +0,0 @@ -[unix_http_server] -file=/tmp/supervisor.sock - -[supervisord] -nodaemon=true -logfile=/tmp/logs/supervisord.log -logfile_maxbytes=50MB -logfile_backups=0 -loglevel=info -pidfile=/tmp/supervisord.pid -minfds=1024 ; min available startup file descriptors -minprocs=200 ; min available process descriptors - -[rpcinterface:supervisor] -supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface - -[supervisorctl] -serverurl=unix:///tmp/supervisor.sock - -[include] -files = /etc/supervisor/conf.d/*.conf \ No newline at end of file diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index c2139f1..0000000 --- a/setup.cfg +++ /dev/null @@ -1,21 +0,0 @@ -[flake8] -max-line-length = 120 -exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules - -[pycodestyle] -max-line-length = 120 -exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules - -[mypy] -python_version = 3.6 -check_untyped_defs = True -ignore_errors = False -ignore_missing_imports = True -strict_optional = True -warn_unused_ignores = True -warn_redundant_casts = True -warn_unused_configs = True - -[mypy-*.migrations.*] -# Django migrations should not produce any errors: -ignore_errors = True