├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.yml
│ └── config.yml
├── dependabot.yml
├── pull_request_template.md
└── workflows
│ ├── publish-develop-dockerhub.yml
│ ├── publish-develop-docs.yml
│ ├── publish-develop-ghcr.yml
│ ├── publish-latest-dockerhub.yml
│ ├── publish-latest-ghcr.yml
│ ├── publish-release-docs.yml
│ ├── test-docs.yml
│ └── test-python.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .pylintrc
├── .vscode
├── extensions.json
└── settings.json
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── Dockerfile
├── LICENSE
├── README.md
├── VERSION
├── conreq
├── __init__.py
├── app_template
│ └── app_name
│ │ ├── .gitignore
│ │ ├── LICENSE
│ │ ├── __init__.py
│ │ ├── app.json
│ │ ├── config.py
│ │ ├── main
│ │ ├── __init__.py
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── migrations
│ │ │ └── __init__.py
│ │ ├── models.py
│ │ ├── tests.py
│ │ ├── urls.py
│ │ └── views.py
│ │ ├── navtabs.py
│ │ ├── package.json
│ │ ├── requirements.txt
│ │ └── settings.py
├── asgi.py
├── core
│ ├── __init__.py
│ ├── api
│ │ ├── __init__.py
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── migrations
│ │ │ └── __init__.py
│ │ ├── models.py
│ │ ├── permissions.py
│ │ ├── serializers.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── arrs
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── helpers.py
│ │ ├── radarr.py
│ │ ├── sonarr.py
│ │ └── tasks.py
│ ├── base
│ │ ├── __init__.py
│ │ ├── apps.py
│ │ ├── fields.py
│ │ ├── forms.py
│ │ ├── helpers.py
│ │ ├── management
│ │ │ ├── __init__.py
│ │ │ └── commands
│ │ │ │ ├── __init__.py
│ │ │ │ ├── preconfig_conreq.py
│ │ │ │ ├── run_conreq.py
│ │ │ │ └── start_conreq_app.py
│ │ ├── migrations
│ │ │ └── __init__.py
│ │ ├── static
│ │ │ ├── css
│ │ │ │ ├── dark.css
│ │ │ │ ├── initialization.css
│ │ │ │ ├── issues.css
│ │ │ │ ├── libraries
│ │ │ │ │ ├── izi_toast_1.4.0.min.css
│ │ │ │ │ └── magnific_popup_1.1.0.css
│ │ │ │ ├── login.css
│ │ │ │ ├── main.css
│ │ │ │ ├── main_slim.css
│ │ │ │ ├── manage_users.css
│ │ │ │ ├── mobile.css
│ │ │ │ ├── modal.css
│ │ │ │ ├── more_info.css
│ │ │ │ ├── navbar.css
│ │ │ │ ├── posters.css
│ │ │ │ ├── server_settings.css
│ │ │ │ ├── sidebar.css
│ │ │ │ ├── simple_posters.css
│ │ │ │ └── viewport.css
│ │ │ ├── icons
│ │ │ │ ├── android-chrome-192x192.png
│ │ │ │ ├── android-chrome-512x512.png
│ │ │ │ ├── apple-touch-icon-114x114-precomposed.png
│ │ │ │ ├── apple-touch-icon-114x114.png
│ │ │ │ ├── apple-touch-icon-120x120-precomposed.png
│ │ │ │ ├── apple-touch-icon-120x120.png
│ │ │ │ ├── apple-touch-icon-144x144-precomposed.png
│ │ │ │ ├── apple-touch-icon-144x144.png
│ │ │ │ ├── apple-touch-icon-152x152-precomposed.png
│ │ │ │ ├── apple-touch-icon-152x152.png
│ │ │ │ ├── apple-touch-icon-180x180-precomposed.png
│ │ │ │ ├── apple-touch-icon-180x180.png
│ │ │ │ ├── apple-touch-icon-57x57-precomposed.png
│ │ │ │ ├── apple-touch-icon-57x57.png
│ │ │ │ ├── apple-touch-icon-60x60-precomposed.png
│ │ │ │ ├── apple-touch-icon-60x60.png
│ │ │ │ ├── apple-touch-icon-72x72-precomposed.png
│ │ │ │ ├── apple-touch-icon-72x72.png
│ │ │ │ ├── apple-touch-icon-76x76-precomposed.png
│ │ │ │ ├── apple-touch-icon-76x76.png
│ │ │ │ ├── apple-touch-icon-precomposed.png
│ │ │ │ ├── apple-touch-icon.png
│ │ │ │ ├── browserconfig.xml
│ │ │ │ ├── favicon-16x16.png
│ │ │ │ ├── favicon-32x32.png
│ │ │ │ ├── favicon.ico
│ │ │ │ ├── maskable.png
│ │ │ │ ├── mstile-150x150.png
│ │ │ │ ├── mstile-310x310.png
│ │ │ │ ├── mstile-70x70.png
│ │ │ │ ├── safari-pinned-tab.svg
│ │ │ │ ├── site.webmanifest
│ │ │ │ └── standard.png
│ │ │ ├── images
│ │ │ │ ├── conreq_logo.png
│ │ │ │ ├── conreq_logo_dark.png
│ │ │ │ ├── person_placeholder.png
│ │ │ │ ├── poster_placeholder.png
│ │ │ │ └── transparent.png
│ │ │ └── js
│ │ │ │ ├── client_websockets.js
│ │ │ │ ├── events_click.js
│ │ │ │ ├── events_generic.js
│ │ │ │ ├── generic_functions.js
│ │ │ │ ├── initialization.js
│ │ │ │ ├── libraries
│ │ │ │ ├── dom_purify_2.2.min.js
│ │ │ │ ├── dom_purify_2.2.min.map
│ │ │ │ ├── izi_toast_1.4.0.min.js
│ │ │ │ └── magnific_popup_1.1.0.min.js
│ │ │ │ ├── modal.js
│ │ │ │ ├── more_info.js
│ │ │ │ ├── sidebar.js
│ │ │ │ ├── sign_up.js
│ │ │ │ ├── toast_messages.js
│ │ │ │ └── viewport.js
│ │ ├── tasks.py
│ │ ├── templates
│ │ │ └── primary
│ │ │ │ ├── base_app.html
│ │ │ │ ├── head_content.html
│ │ │ │ ├── head_content_slim.html
│ │ │ │ ├── icons.html
│ │ │ │ ├── loading_animation.html
│ │ │ │ ├── loading_animation_container.html
│ │ │ │ ├── navbar.html
│ │ │ │ ├── searchbar.html
│ │ │ │ └── sidebar.html
│ │ ├── templatetags
│ │ │ ├── __init__.py
│ │ │ └── conreq_tags.py
│ │ ├── urls.py
│ │ ├── validators.py
│ │ └── views.py
│ ├── discover
│ │ ├── __init__.py
│ │ ├── apps.py
│ │ ├── helpers.py
│ │ ├── migrations
│ │ │ └── __init__.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── issue_reporting
│ │ ├── __init__.py
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── helpers.py
│ │ ├── migrations
│ │ │ ├── 0001_initial.py
│ │ │ ├── 0002_auto_20210203_1912.py
│ │ │ ├── 0003_auto_20210203_1917.py
│ │ │ ├── 0004_auto_20210203_2153.py
│ │ │ ├── 0005_auto_20210203_2248.py
│ │ │ ├── 0006_auto_20210203_2302.py
│ │ │ ├── 0007_auto_20210204_0207.py
│ │ │ ├── 0008_auto_20210206_0020.py
│ │ │ ├── 0009_auto_20210206_0405.py
│ │ │ ├── 0010_alter_reportedissue_id.py
│ │ │ ├── 0011_auto_20210621_2105.py
│ │ │ ├── 0012_rename_manually_resolved_reportedissue_resolved.py
│ │ │ ├── 0013_remove_reportedissue_resolutions.py
│ │ │ ├── 0014_reportedissue_resolutions.py
│ │ │ ├── 0015_auto_20210705_2244.py
│ │ │ ├── 0016_auto_20210705_2248.py
│ │ │ ├── 0017_remove_reportedissue_source.py
│ │ │ ├── 0018_alter_reportedissue_resolutions.py
│ │ │ ├── 0019_reportedissue_auto_resolve_in_progress.py
│ │ │ └── __init__.py
│ │ ├── models.py
│ │ ├── tasks.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── manage_users
│ │ ├── __init__.py
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── migrations
│ │ │ ├── 0001_initial.py
│ │ │ ├── 0002_profile_http_header_auth_user.py
│ │ │ ├── 0003_alter_profile_id.py
│ │ │ ├── 0004_rename_http_header_auth_user_profile_externally_authenticated.py
│ │ │ └── __init__.py
│ │ ├── models.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── more_info
│ │ ├── __init__.py
│ │ ├── apps.py
│ │ ├── helpers.py
│ │ ├── migrations
│ │ │ └── __init__.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── password_reset
│ │ ├── __init__.py
│ │ ├── apps.py
│ │ ├── forms.py
│ │ ├── templates
│ │ │ └── conreq
│ │ │ │ ├── password_reset.html
│ │ │ │ ├── password_reset_confirm.html
│ │ │ │ └── password_reset_sent.html
│ │ ├── urls.py
│ │ └── views.py
│ ├── pwa
│ │ ├── LICENSE.md
│ │ ├── __init__.py
│ │ ├── app_settings.py
│ │ ├── apps.py
│ │ ├── migrations
│ │ │ └── __init__.py
│ │ ├── templates
│ │ │ ├── manifest.json
│ │ │ ├── offline.html
│ │ │ ├── pwa.html
│ │ │ └── serviceworker.js
│ │ ├── templatetags
│ │ │ ├── __init__.py
│ │ │ └── pwa.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── search
│ │ ├── __init__.py
│ │ ├── apps.py
│ │ ├── migrations
│ │ │ └── __init__.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── server_settings
│ │ ├── __init__.py
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── migrations
│ │ │ ├── 0001_initial.py
│ │ │ ├── 0002_auto_20210118_2004.py
│ │ │ ├── 0003_conreqconfig_conreq_initialized.py
│ │ │ ├── 0004_auto_20210119_1742.py
│ │ │ ├── 0005_auto_20210127_0107.py
│ │ │ ├── 0006_auto_20210130_0236.py
│ │ │ ├── 0007_conreqconfig_conreq_http_header_auth.py
│ │ │ ├── 0008_auto_20210203_0053.py
│ │ │ ├── 0009_auto_20210204_1938.py
│ │ │ ├── 0010_auto_20210205_2326.py
│ │ │ ├── 0011_auto_20210205_2343.py
│ │ │ ├── 0012_auto_20210209_2144.py
│ │ │ ├── 0013_conreqconfig_conreq_allow_tv_specials.py
│ │ │ ├── 0014_auto_20210313_0231.py
│ │ │ ├── 0015_remove_conreqconfig_conreq_app_name.py
│ │ │ ├── 0016_alter_conreqconfig_id.py
│ │ │ ├── 0017_remove_conreqconfig_conreq_dark_theme.py
│ │ │ ├── 0018_auto_20210428_2039.py
│ │ │ ├── 0019_remove_conreqconfig_conreq_api_key.py
│ │ │ └── __init__.py
│ │ ├── models.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── sign_up
│ │ ├── __init__.py
│ │ ├── apps.py
│ │ ├── forms.py
│ │ ├── migrations
│ │ │ └── __init__.py
│ │ ├── templates
│ │ │ ├── modal
│ │ │ │ ├── default.html
│ │ │ │ └── manage_user.html
│ │ │ └── registration
│ │ │ │ ├── initialization.html
│ │ │ │ ├── sign_in.html
│ │ │ │ └── sign_up.html
│ │ ├── urls.py
│ │ └── views.py
│ ├── tmdb
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── discovery.py
│ │ ├── preset_filters.py
│ │ ├── search.py
│ │ └── templates
│ │ │ ├── cards
│ │ │ ├── artwork.html
│ │ │ ├── casted.html
│ │ │ ├── issue.html
│ │ │ ├── person.html
│ │ │ ├── poster.html
│ │ │ └── review.html
│ │ │ ├── compressed
│ │ │ └── simple_posters_css.html
│ │ │ ├── dropdown
│ │ │ └── item.html
│ │ │ ├── modal
│ │ │ ├── content_preview.html
│ │ │ ├── discover_filter_advanced.html
│ │ │ ├── discover_filter_simple.html
│ │ │ ├── report_issue.html
│ │ │ └── series_selection.html
│ │ │ └── viewport
│ │ │ ├── components
│ │ │ ├── more_info_collection.html
│ │ │ ├── more_info_recommended.html
│ │ │ ├── server_settings_radarr.html
│ │ │ └── server_settings_sonarr.html
│ │ │ ├── discover.html
│ │ │ ├── manage_users.html
│ │ │ ├── more_info.html
│ │ │ ├── person.html
│ │ │ ├── reported_issues.html
│ │ │ ├── requests.html
│ │ │ ├── search.html
│ │ │ └── server_settings.html
│ ├── user_requests
│ │ ├── __init__.py
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── helpers.py
│ │ ├── migrations
│ │ │ ├── 0001_initial.py
│ │ │ ├── 0002_userrequest_date_requested.py
│ │ │ ├── 0003_alter_userrequest_id.py
│ │ │ ├── 0004_alter_userrequest_requested_by.py
│ │ │ ├── 0005_remove_userrequest_source.py
│ │ │ └── __init__.py
│ │ ├── models.py
│ │ ├── tasks.py
│ │ ├── urls.py
│ │ └── views.py
│ └── websockets
│ │ ├── __init__.py
│ │ └── consumers.py
├── settings.py
├── urls.py
└── utils
│ ├── __init__.py
│ ├── cache.py
│ ├── database.py
│ ├── debug.py
│ ├── environment.py
│ ├── generic.py
│ ├── log.py
│ ├── threads.py
│ └── user_apps.py
├── docs
├── mkdocs.yml
└── src
│ ├── configure
│ ├── env_vars.md
│ ├── mysql.md
│ ├── organizr.md
│ ├── static_files.md
│ └── webserver.md
│ ├── contrib
│ ├── apps.md
│ └── docs.md
│ ├── develop
│ ├── build_docker.md
│ ├── creating_apps.md
│ └── run_conreq.md
│ ├── dictionary.txt
│ ├── index.md
│ └── install
│ ├── docker.md
│ └── nssm.md
├── manage.py
├── misc
├── branding
│ ├── circle.ai
│ ├── circle.png
│ ├── circle_outline.ai
│ ├── circle_outline.png
│ ├── conreq_logo.png
│ ├── conreq_logo.psd
│ ├── conreq_logo_dark.png
│ ├── conreq_logo_dark.psd
│ ├── conreq_square.ai
│ ├── conreq_square.png
│ ├── no_bg_dark.ai
│ ├── no_bg_dark.png
│ ├── no_bg_gradient.ai
│ ├── no_bg_gradient.png
│ ├── no_bg_light.ai
│ ├── no_bg_light.png
│ ├── rounded_square.ai
│ ├── rounded_square.png
│ ├── rounded_square_outline.ai
│ └── rounded_square_outline.png
├── legal
│ ├── fontawesome_attribution.js
│ └── fontawesome_license.txt
├── other
│ ├── person_placeholder.psd
│ └── poster_placeholder.psd
└── screenshots
│ ├── desktop_discover.png
│ ├── desktop_modal_episode_selection.png
│ ├── desktop_modal_filter.png
│ ├── desktop_modal_preview.png
│ ├── desktop_more_info.png
│ ├── desktop_registration.png
│ ├── desktop_sign_in.png
│ ├── mobile_discover.png
│ ├── mobile_modal_episode_selection.png
│ ├── mobile_modal_filter.png
│ ├── mobile_more_info.png
│ ├── mobile_registration.png
│ ├── mobile_sidebar.png
│ └── mobile_sign_in.png
├── requirements.txt
└── requirements
├── dev.txt
├── docs.txt
└── main.txt
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [Archmonger] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
13 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.yml:
--------------------------------------------------------------------------------
1 | name: Bug Report
2 | description: Report a bug with Conreq software.
3 | labels: [Bug]
4 | body:
5 | - type: input
6 | attributes:
7 | label: Conreq Version
8 | description: What version did you encounter this issue on?
9 | placeholder: For example... 1.25.0
10 | validations:
11 | required: true
12 |
13 | - type: dropdown
14 | attributes:
15 | label: Conreq Branch
16 | options:
17 | - Latest / Main
18 | - Develop
19 | - Other
20 | validations:
21 | required: true
22 |
23 | - type: dropdown
24 | attributes:
25 | label: Server Operating System
26 | multiple: true
27 | options:
28 | - Windows
29 | - Linux
30 | - FreeBSD
31 | - MacOS
32 | - N/A
33 | validations:
34 | required: true
35 |
36 | - type: dropdown
37 | attributes:
38 | label: Client Operating System
39 | multiple: true
40 | options:
41 | - Windows
42 | - Linux
43 | - FreeBSD
44 | - MacOS
45 | - Android
46 | - iOS
47 | - N/A
48 | validations:
49 | required: true
50 |
51 | - type: dropdown
52 | attributes:
53 | label: Web Browser(s)
54 | multiple: true
55 | options:
56 | - Firefox
57 | - Chrome
58 | - Safari
59 | - Microsoft Edge
60 | - N/A
61 | validations:
62 | required: true
63 |
64 | - type: textarea
65 | attributes:
66 | label: Description
67 | validations:
68 | required: true
69 |
70 | - type: textarea
71 | attributes:
72 | label: Log Info
73 | description: Copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
74 | render: shell
75 | validations:
76 | required: false
77 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: Feature Request
4 | url: https://github.com/Archmonger/Conreq/discussions/categories/feature-requests
5 | about: Click "New Discussion" to create a feature request. See an idea you like? Vote for it!
6 | - name: Discord Support
7 | url: https://discord.gg/gQhGZzEjmX
8 | about: Ask a question within the support channel.
9 | - name: GitHub Community Support
10 | url: https://github.com/Archmonger/Conreq/discussions/categories/support
11 | about: Click "New Discussion" to create a support ticket.
12 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "pip"
4 | directory: "/requirements/"
5 | schedule:
6 | interval: "daily"
7 | target-branch: "main"
8 | open-pull-requests-limit: 20
9 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | ## Description
2 |
3 |
4 |
5 | ## Checklist
6 |
7 | Please update this checklist as you complete each item:
8 |
9 | - [ ] Tests have been developed for bug fixes or new functionality.
10 | - [ ] The changelog has been updated, if necessary.
11 | - [ ] Documentation has been updated, if necessary.
12 | - [ ] GitHub Issues closed by this PR have been linked.
13 |
14 | By submitting this pull request I agree that all contributions comply with this project's open source license(s).
15 |
--------------------------------------------------------------------------------
/.github/workflows/publish-develop-dockerhub.yml:
--------------------------------------------------------------------------------
1 | name: Publish Develop to DockerHub
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | jobs:
9 | docker:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Set up QEMU
13 | uses: docker/setup-qemu-action@v3
14 | - name: Set up Docker Buildx
15 | uses: docker/setup-buildx-action@v3
16 | - name: Login to Docker Hub
17 | uses: docker/login-action@v3
18 | with:
19 | username: ${{ secrets.DOCKERHUB_USERNAME }}
20 | password: ${{ secrets.DOCKERHUB_TOKEN }}
21 | - name: Build and push to Docker Hub
22 | uses: docker/build-push-action@v6
23 | with:
24 | push: true
25 | tags: archmonger/conreq:develop
26 |
--------------------------------------------------------------------------------
/.github/workflows/publish-develop-docs.yml:
--------------------------------------------------------------------------------
1 | name: Publish Develop Docs
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | jobs:
8 | deploy:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@v4
12 | with:
13 | fetch-depth: 0
14 | - uses: actions/setup-python@v5
15 | with:
16 | python-version: 3.x
17 | - run: pip install -r requirements/docs.txt
18 | - name: Publish Develop Docs
19 | run: |
20 | git config user.name github-actions
21 | git config user.email github-actions@github.com
22 | cd docs
23 | mike deploy --push develop
24 |
--------------------------------------------------------------------------------
/.github/workflows/publish-develop-ghcr.yml:
--------------------------------------------------------------------------------
1 | name: Publish Develop to GHCR
2 |
3 | on:
4 | push:
5 | branches:
6 | - develmainop
7 |
8 | jobs:
9 | docker:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Set up QEMU
13 | uses: docker/setup-qemu-action@v3
14 | - name: Set up Docker Buildx
15 | uses: docker/setup-buildx-action@v3
16 | - name: Login to GitHub Container Registry
17 | uses: docker/login-action@v3
18 | with:
19 | registry: ghcr.io
20 | username: ${{ github.actor }}
21 | password: ${{ github.token }}
22 | - name: Build and push to GitHub Container Registry
23 | uses: docker/build-push-action@v6
24 | with:
25 | push: true
26 | tags: ghcr.io/archmonger/conreq:develop
27 |
--------------------------------------------------------------------------------
/.github/workflows/publish-latest-dockerhub.yml:
--------------------------------------------------------------------------------
1 | name: Publish Latest to DockerHub
2 |
3 | on:
4 | release:
5 | types: [published]
6 |
7 | jobs:
8 | docker:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - name: Set up QEMU
12 | uses: docker/setup-qemu-action@v3
13 | - name: Set up Docker Buildx
14 | uses: docker/setup-buildx-action@v3
15 | - name: Login to Docker Hub
16 | uses: docker/login-action@v3
17 | with:
18 | username: ${{ secrets.DOCKERHUB_USERNAME }}
19 | password: ${{ secrets.DOCKERHUB_TOKEN }}
20 | - name: Build and push to Docker Hub
21 | uses: docker/build-push-action@v6
22 | with:
23 | push: true
24 | tags: archmonger/conreq:latest,archmonger/conreq:${{ github.event.release.tag_name }}
25 |
--------------------------------------------------------------------------------
/.github/workflows/publish-latest-ghcr.yml:
--------------------------------------------------------------------------------
1 | name: Publish Latest to GHCR
2 |
3 | on:
4 | release:
5 | types: [published]
6 |
7 | jobs:
8 | docker:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - name: Set up QEMU
12 | uses: docker/setup-qemu-action@v3
13 | - name: Set up Docker Buildx
14 | uses: docker/setup-buildx-action@v3
15 | - name: Login to Docker Hub
16 | uses: docker/login-action@v3
17 | with:
18 | registry: ghcr.io
19 | username: ${{ github.actor }}
20 | password: ${{ github.token }}
21 | - name: Build and push to Docker Hub
22 | uses: docker/build-push-action@v6
23 | with:
24 | push: true
25 | tags: ghcr.io/archmonger/conreq:latest,ghcr.io/archmonger/conreq:${{ github.event.release.tag_name }}
26 |
--------------------------------------------------------------------------------
/.github/workflows/publish-release-docs.yml:
--------------------------------------------------------------------------------
1 | name: Publish Release Docs
2 |
3 | on:
4 | release:
5 | types: [published]
6 |
7 | jobs:
8 | deploy:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@v4
12 | with:
13 | fetch-depth: 0
14 | - uses: actions/setup-python@v5
15 | with:
16 | python-version: 3.x
17 | - run: pip install -r requirements/docs.txt
18 | - name: Publish ${{ github.event.release.name }} Docs
19 | run: |
20 | git config user.name github-actions
21 | git config user.email github-actions@github.com
22 | cd docs
23 | mike deploy --push --update-aliases ${{ github.event.release.name }} latest
24 |
--------------------------------------------------------------------------------
/.github/workflows/test-docs.yml:
--------------------------------------------------------------------------------
1 | name: Documentation Tests
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 | branches:
9 | - main
10 | schedule:
11 | - cron: "0 0 * * 0"
12 |
13 | jobs:
14 | docs:
15 | runs-on: ubuntu-latest
16 | steps:
17 | - uses: actions/checkout@v4
18 | with:
19 | fetch-depth: 0
20 | - uses: actions/setup-python@v5
21 | with:
22 | python-version: 3.x
23 | - name: Check docs build
24 | run: |
25 | pip install -r requirements/docs.txt
26 | linkcheckMarkdown docs/ -v -r
27 | linkcheckMarkdown README.md -v -r
28 | linkcheckMarkdown CHANGELOG.md -v -r
29 | cd docs
30 | mkdocs build --strict
31 |
--------------------------------------------------------------------------------
/.github/workflows/test-python.yml:
--------------------------------------------------------------------------------
1 | name: Django Tests
2 |
3 | on:
4 | push:
5 | branches: [main]
6 | pull_request:
7 | branches: [main]
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 | strategy:
13 | max-parallel: 4
14 | matrix:
15 | python-version: [3.11]
16 |
17 | steps:
18 | - uses: actions/checkout@v2
19 | - name: Set up Python ${{ matrix.python-version }}
20 | uses: actions/setup-python@v2
21 | with:
22 | python-version: ${{ matrix.python-version }}
23 | - name: Install Dependencies
24 | run: |
25 | python -m pip install --upgrade pip
26 | pip install -r requirements.txt
27 | - name: Run Tests
28 | run: |
29 | python manage.py test --noinput --parallel
30 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Django #
2 | logs
3 | *.log
4 | *.pot
5 | *.pyc
6 | .dccache
7 | __pycache__
8 | *.sqlite3
9 | data/
10 |
11 | # Temp files
12 | *.tmp
13 |
14 | # Docker config folder
15 | config/
16 |
17 | # Backup files #
18 | *.bak
19 | *_bak/
20 |
21 | # If you are using PyCharm #
22 | .idea/**/workspace.xml
23 | .idea/**/tasks.xml
24 | .idea/dictionaries
25 | .idea/**/dataSources/
26 | .idea/**/dataSources.ids
27 | .idea/**/dataSources.xml
28 | .idea/**/dataSources.local.xml
29 | .idea/**/sqlDataSources.xml
30 | .idea/**/dynamic.xml
31 | .idea/**/uiDesigner.xml
32 | .idea/**/gradle.xml
33 | .idea/**/libraries
34 | *.iws /out/
35 |
36 | # Python #
37 | *.py[cod]
38 | *$py.class
39 |
40 | # Distribution / packaging
41 | .Python build/
42 | develop-eggs/
43 | dist/
44 | downloads/
45 | eggs/
46 | .eggs/
47 | lib/
48 | lib64/
49 | parts/
50 | sdist/
51 | var/
52 | wheels/
53 | *.egg-info/
54 | .installed.cfg
55 | *.egg
56 | *.manifest
57 | *.spec
58 |
59 | # Installer logs
60 | pip-log.txt
61 | pip-delete-this-directory.txt
62 |
63 | # Unit test / coverage reports
64 | htmlcov/
65 | .tox/
66 | .coverage
67 | .coverage.*
68 | .cache
69 | .pytest_cache/
70 | nosetests.xml
71 | coverage.xml
72 | *.cover
73 | .hypothesis/
74 |
75 | # Jupyter Notebook
76 | .ipynb_checkpoints
77 |
78 | # pyenv
79 | .python-version
80 |
81 | # celery
82 | celerybeat-schedule.*
83 |
84 | # SageMath parsed files
85 | *.sage.py
86 |
87 | # Environments
88 | .env/
89 | .venv/
90 | env/
91 | venv/
92 | ENV/
93 | env.bak/
94 | venv.bak/
95 |
96 | # mypy
97 | .mypy_cache/
98 |
99 | # Sublime Text #
100 | *.tmlanguage.cache
101 | *.tmPreferences.cache
102 | *.stTheme.cache
103 | *.sublime-workspace
104 | *.sublime-project
105 |
106 | # sftp configuration file
107 | sftp-config.json
108 |
109 | # Package control specific files Package
110 | Control.last-run
111 | Control.ca-list
112 | Control.ca-bundle
113 | Control.system-ca-bundle
114 | GitHub.sublime-settings
115 |
116 | # Visual Studio Code #
117 | .vscode/*
118 | !.vscode/settings.json
119 | !.vscode/extensions.json
120 | .history/
121 | %SystemDrive%
122 |
123 | # Mac file system
124 | .DS_Store/
125 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: https://github.com/pre-commit/pre-commit-hooks
3 | rev: "v4.6.0"
4 | hooks:
5 | - id: check-merge-conflict
6 |
--------------------------------------------------------------------------------
/.pylintrc:
--------------------------------------------------------------------------------
1 | [MASTER]
2 | ignore=migrations
3 | disable=broad-except, fixme
4 | load-plugins=pylint_django
5 | django-settings-module=conreq.settings
6 | [FORMAT]
7 | max-line-length=150
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "irongeek.vscode-env",
4 | "eamodio.gitlens",
5 | "github.vscode-pull-request-github",
6 | "wholroyd.jinja",
7 | "esbenp.prettier-vscode",
8 | "ms-python.vscode-pylance",
9 | "ms-python.python",
10 | "mrmlnc.vscode-autoprefixer",
11 | "gruntfuggly.todo-tree"
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.detectIndentation": false,
3 | "editor.formatOnSave": true,
4 | "python.languageServer": "Pylance",
5 | "terminal.integrated.scrollback": 2000,
6 | "git.autofetch": true,
7 | "prettier.tabWidth": 4,
8 | "prettier.useTabs": true,
9 | "prettier.endOfLine": "auto",
10 | "autoprefixer.formatOnSave": true,
11 | "files.associations": {
12 | "**/requirements/*.txt": "pip-requirements",
13 | },
14 | "[jsonc]": {
15 | "editor.defaultFormatter": "vscode.json-language-features"
16 | },
17 | "[json]": {
18 | "editor.defaultFormatter": "vscode.json-language-features"
19 | },
20 | "[javascript]": {
21 | "editor.defaultFormatter": "esbenp.prettier-vscode"
22 | },
23 | "[css]": {
24 | "editor.defaultFormatter": "esbenp.prettier-vscode"
25 | },
26 | "[python]": {
27 | "editor.defaultFormatter": "charliermarsh.ruff"
28 | },
29 | }
30 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/CHANGELOG.md
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # FROM ghcr.io/linuxserver/baseimage-alpine:3.20
2 | FROM python:3.11.9-alpine3.20
3 |
4 | ENV DATA_DIR=/config DEBUG=False
5 |
6 | COPY ./manage.py /app/manage.py
7 | COPY ./VERSION /app/VERSION
8 | COPY ./LICENSE /app/LICENSE
9 | COPY ./conreq/ /app/conreq/
10 | COPY ./requirements/ /app/conreq/requirements/
11 |
12 | RUN \
13 | echo "**** Install build dependencies ****" \
14 | && \
15 | apk add --no-cache --virtual=build-dependencies \
16 | bsd-compat-headers \
17 | build-base \
18 | cargo \
19 | curl \
20 | g++ \
21 | gcc \
22 | git \
23 | jq \
24 | libev-dev \
25 | libffi-dev \
26 | openssl-dev \
27 | && \
28 | echo "**** Install Linux packages ****" \
29 | && \
30 | apk add --no-cache \
31 | freetype-dev \
32 | fribidi-dev \
33 | harfbuzz-dev \
34 | jpeg-dev \
35 | lcms2-dev \
36 | openjpeg-dev \
37 | tcl-dev \
38 | tiff-dev \
39 | tk-dev \
40 | zlib-dev \
41 | && \
42 | echo "**** Install Python dependencies ****" \
43 | && \
44 | pip3 install --no-cache-dir -U -r /app/conreq/requirements/main.txt \
45 | && \
46 | echo "**** Cleanup ****" \
47 | && \
48 | apk del --purge \
49 | build-dependencies \
50 | && \
51 | rm -rf \
52 | /root/.cache \
53 | /root/.cargo \
54 | /tmp/*
55 |
56 | EXPOSE 7575
57 |
58 | WORKDIR /app/
59 | CMD ["sh", "-c", "python3 manage.py run_conreq --uid ${PUID:=99} --gid ${PGID:=100}"]
60 |
--------------------------------------------------------------------------------
/VERSION:
--------------------------------------------------------------------------------
1 | 0.21.1
2 |
--------------------------------------------------------------------------------
/conreq/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/__init__.py
--------------------------------------------------------------------------------
/conreq/app_template/app_name/.gitignore:
--------------------------------------------------------------------------------
1 | # Django #
2 | logs
3 | *.log
4 | *.pot
5 | *.pyc
6 | .dccache
7 | __pycache__
8 | db.sqlite3
9 | media
10 | cache
11 | collectstatic
12 | data
13 | settings.json
14 |
15 | # Backup files #
16 | *.bak
17 |
18 | # If you are using PyCharm #
19 | .idea/**/workspace.xml
20 | .idea/**/tasks.xml
21 | .idea/dictionaries
22 | .idea/**/dataSources/
23 | .idea/**/dataSources.ids
24 | .idea/**/dataSources.xml
25 | .idea/**/dataSources.local.xml
26 | .idea/**/sqlDataSources.xml
27 | .idea/**/dynamic.xml
28 | .idea/**/uiDesigner.xml
29 | .idea/**/gradle.xml
30 | .idea/**/libraries
31 | *.iws /out/
32 |
33 | # Python #
34 | *.py[cod]
35 | *$py.class
36 |
37 | # Distribution / packaging
38 | .Python build/
39 | develop-eggs/
40 | dist/
41 | downloads/
42 | eggs/
43 | .eggs/
44 | lib/
45 | lib64/
46 | parts/
47 | sdist/
48 | var/
49 | wheels/
50 | *.egg-info/
51 | .installed.cfg
52 | *.egg
53 | *.manifest
54 | *.spec
55 |
56 | # Installer logs
57 | pip-log.txt
58 | pip-delete-this-directory.txt
59 |
60 | # Unit test / coverage reports
61 | htmlcov/
62 | .tox/
63 | .coverage
64 | .coverage.*
65 | .cache
66 | .pytest_cache/
67 | nosetests.xml
68 | coverage.xml
69 | *.cover
70 | .hypothesis/
71 |
72 | # Jupyter Notebook
73 | .ipynb_checkpoints
74 |
75 | # pyenv
76 | .python-version
77 |
78 | # celery
79 | celerybeat-schedule.*
80 |
81 | # SageMath parsed files
82 | *.sage.py
83 |
84 | # Environments
85 | .env
86 | .venv
87 | env/
88 | venv/
89 | ENV/
90 | env.bak/
91 | venv.bak/
92 |
93 | # mkdocs documentation
94 | /site
95 |
96 | # mypy
97 | .mypy_cache/
98 |
99 | # Sublime Text #
100 | *.tmlanguage.cache
101 | *.tmPreferences.cache
102 | *.stTheme.cache
103 | *.sublime-workspace
104 | *.sublime-project
105 |
106 | # sftp configuration file
107 | sftp-config.json
108 |
109 | # Package control specific files Package
110 | Control.last-run
111 | Control.ca-list
112 | Control.ca-bundle
113 | Control.system-ca-bundle
114 | GitHub.sublime-settings
115 |
116 | # Visual Studio Code #
117 | .vscode
118 | .vscode/*
119 | .vscode/settings.json
120 | .vscode/tasks.json
121 | .vscode/launch.json
122 | .vscode/extensions.json
123 | .history
124 | %SystemDrive%
125 |
126 | # Mac file system
127 | .DS_Store
--------------------------------------------------------------------------------
/conreq/app_template/app_name/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/app_template/app_name/__init__.py
--------------------------------------------------------------------------------
/conreq/app_template/app_name/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "app_name": "",
3 | "app_version": "",
4 | "description": "",
5 | "notice_msg": "",
6 | "gh_author": "",
7 | "repository_url": "",
8 | "homepage_url": "",
9 | "support_url": "",
10 | "donation_url": "",
11 | "env_variables": [],
12 | "categories": [],
13 | "development_stage": "",
14 | "mobile_compatible": false,
15 | "min_conreq_version": "",
16 | "tested_conreq_version": "",
17 | "max_conreq_version": "",
18 | "optional_apps": [""],
19 | "required_apps": [""],
20 | "incompatible_apps": [""],
21 | "incompatible_app_categories": []
22 | }
23 |
--------------------------------------------------------------------------------
/conreq/app_template/app_name/config.py:
--------------------------------------------------------------------------------
1 | # App configuration parameters used by Conreq
2 | HEAD_TEMPLATES = []
3 | BODY_TEMPLATES = []
4 | INIT_COMMANDS = []
5 | PRECONFIGURE_COMMANDS = []
6 | SPLASH_TEMPLATE = ""
7 | LOGIN_TEMPLATE = ""
8 | BASE_TEMPLATE = ""
9 |
--------------------------------------------------------------------------------
/conreq/app_template/app_name/main/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/app_template/app_name/main/__init__.py
--------------------------------------------------------------------------------
/conreq/app_template/app_name/main/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | # Register your models here.
4 |
--------------------------------------------------------------------------------
/conreq/app_template/app_name/main/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class {{ camel_case_app_name }}Config(AppConfig):
5 | default_auto_field = 'django.db.models.BigAutoField'
6 | name = '{{ app_name }}.main'
7 |
--------------------------------------------------------------------------------
/conreq/app_template/app_name/main/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/app_template/app_name/main/migrations/__init__.py
--------------------------------------------------------------------------------
/conreq/app_template/app_name/main/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | # Create your models here.
4 |
--------------------------------------------------------------------------------
/conreq/app_template/app_name/main/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/conreq/app_template/app_name/main/urls.py:
--------------------------------------------------------------------------------
1 | app_name = "{{ app_name }}"
2 | urlpattern = []
3 |
--------------------------------------------------------------------------------
/conreq/app_template/app_name/main/views.py:
--------------------------------------------------------------------------------
1 | from django.shortcuts import render
2 |
3 | # Create your views here.
4 |
--------------------------------------------------------------------------------
/conreq/app_template/app_name/navtabs.py:
--------------------------------------------------------------------------------
1 | from django.urls import reverse
2 |
3 | USER_NAVTABS = []
4 | ADMIN_NAVTABS = []
5 | CUSTOM_NAVTABS = {}
6 | SETTINGS_TABS = []
7 |
--------------------------------------------------------------------------------
/conreq/app_template/app_name/package.json:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/conreq/app_template/app_name/requirements.txt:
--------------------------------------------------------------------------------
1 | # Any requirements in here will be automatically installed by Conreq
--------------------------------------------------------------------------------
/conreq/app_template/app_name/settings.py:
--------------------------------------------------------------------------------
1 | # CAUTION: Anything in here will get automatically added into Conreq's Django settings file.
2 | # For more information, see the following docs:
3 | # https://docs.djangoproject.com/en/3.2/topics/settings/
4 | # https://github.com/sobolevn/django-split-settings
5 |
--------------------------------------------------------------------------------
/conreq/asgi.py:
--------------------------------------------------------------------------------
1 | """
2 | ASGI config for Conreq project.
3 |
4 | It exposes the ASGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/
8 | """
9 | # pylint: disable=wrong-import-position
10 | from django.core.asgi import get_asgi_application
11 | from django.urls import path
12 |
13 | # Fetch ASGI application before importing dependencies that require ORM models.
14 | django_asgi_app = get_asgi_application()
15 |
16 | from channels.auth import AuthMiddlewareStack
17 | from channels.routing import ProtocolTypeRouter, URLRouter
18 | from channels.security.websocket import AllowedHostsOriginValidator
19 |
20 | from conreq.core.websockets.consumers import CommandConsumer
21 | from conreq.utils.environment import get_base_url
22 |
23 | BASE_URL = get_base_url()
24 | if BASE_URL:
25 | BASE_URL = BASE_URL[1:]
26 |
27 |
28 | class LifespanApp:
29 | # pylint: disable=too-few-public-methods
30 | """
31 | Temporary shim for https://github.com/django/channels/issues/1216
32 | Needed so that hypercorn doesn't display an error.
33 | """
34 |
35 | def __init__(self, scope):
36 | self.scope = scope
37 |
38 | async def __call__(self, receive, send):
39 | if self.scope["type"] == "lifespan":
40 | while True:
41 | message = await receive()
42 | if message["type"] == "lifespan.startup":
43 | await send({"type": "lifespan.startup.complete"})
44 | elif message["type"] == "lifespan.shutdown":
45 | await send({"type": "lifespan.shutdown.complete"})
46 | return
47 |
48 |
49 | application = ProtocolTypeRouter(
50 | {
51 | # ASGI app has concurrency problems, see
52 | # See https://github.com/django/channels/issues/1587
53 | "http": django_asgi_app,
54 | "websocket": AllowedHostsOriginValidator(
55 | AuthMiddlewareStack(
56 | URLRouter([path(BASE_URL, CommandConsumer().as_asgi())])
57 | )
58 | ),
59 | "lifespan": LifespanApp,
60 | }
61 | )
62 |
--------------------------------------------------------------------------------
/conreq/core/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/__init__.py
--------------------------------------------------------------------------------
/conreq/core/api/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/api/__init__.py
--------------------------------------------------------------------------------
/conreq/core/api/admin.py:
--------------------------------------------------------------------------------
1 | from rest_framework.authtoken.admin import TokenAdmin
2 |
3 | # Register your models here.
4 |
5 | TokenAdmin.raw_id_fields = ["user"]
6 |
--------------------------------------------------------------------------------
/conreq/core/api/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class ApiConfig(AppConfig):
5 | default_auto_field = "django.db.models.BigAutoField"
6 | name = "conreq.core.api"
7 |
--------------------------------------------------------------------------------
/conreq/core/api/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/api/migrations/__init__.py
--------------------------------------------------------------------------------
/conreq/core/api/models.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth import get_user_model
2 | from django.db.models.signals import post_save
3 | from django.dispatch import receiver
4 | from rest_framework.authtoken.models import Token
5 |
6 | User = get_user_model()
7 |
8 | # Create your models here.
9 | @receiver(post_save, sender=User)
10 | def create_auth_token(
11 | sender, instance=None, created=False, **kwargs
12 | ): # pylint: disable=unused-argument
13 | # Create the token if it doesn't exist
14 | if not hasattr(instance, "auth_token"):
15 | Token.objects.create(user=instance)
16 |
--------------------------------------------------------------------------------
/conreq/core/api/permissions.py:
--------------------------------------------------------------------------------
1 | import typing
2 |
3 | from django.http import HttpRequest
4 | from rest_framework_api_key.models import APIKey
5 | from rest_framework_api_key.permissions import BaseHasAPIKey, KeyParser
6 |
7 |
8 | class HasAPIKey(BaseHasAPIKey):
9 | model = APIKey
10 | key_parser = KeyParser()
11 |
12 | def get_key(self, request: HttpRequest) -> typing.Optional[str]:
13 | # Prefer key in header
14 | header_key = self.key_parser.get(request)
15 | if header_key:
16 | return header_key
17 | # Fallback to key in URL parameters
18 | return request.GET.get("apikey")
19 |
--------------------------------------------------------------------------------
/conreq/core/api/serializers.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth import get_user_model
2 | from rest_framework import serializers
3 |
4 | from conreq.core.manage_users.models import Profile
5 |
6 |
7 | class UserProfileSerializer(serializers.ModelSerializer):
8 | class Meta:
9 | model = Profile
10 | fields = ["language", "externally_authenticated"]
11 |
12 |
13 | class UserSerializer(serializers.ModelSerializer):
14 | profile = UserProfileSerializer(required=True)
15 |
16 | class Meta:
17 | model = get_user_model()
18 | fields = [
19 | "id",
20 | "last_login",
21 | "is_superuser",
22 | "username",
23 | "first_name",
24 | "last_name",
25 | "email",
26 | "is_staff",
27 | "is_active",
28 | "date_joined",
29 | "groups",
30 | "user_permissions",
31 | "profile",
32 | "auth_token",
33 | ]
34 |
--------------------------------------------------------------------------------
/conreq/core/arrs/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/arrs/__init__.py
--------------------------------------------------------------------------------
/conreq/core/arrs/helpers.py:
--------------------------------------------------------------------------------
1 | from time import sleep
2 |
3 | from conreq.core.arrs.sonarr import SonarrManager
4 |
5 |
6 | def wait_for_series_info(tvdb_id, max_retries=15):
7 | """Keeps attempting to fetch a series from Sonarr until it becomes available"""
8 | sonarr_manager = SonarrManager()
9 | series = sonarr_manager.get(
10 | tvdb_id=tvdb_id, obtain_season_info=True, force_update_cache=True
11 | )
12 | if series is None:
13 | series_fetch_retries = 0
14 | while series is None:
15 | if series_fetch_retries > max_retries:
16 | break
17 | series_fetch_retries = series_fetch_retries + 1
18 | series = sonarr_manager.get(
19 | tvdb_id=tvdb_id, obtain_season_info=True, force_update_cache=True
20 | )
21 | sleep(0.25)
22 | return series
23 |
--------------------------------------------------------------------------------
/conreq/core/arrs/tasks.py:
--------------------------------------------------------------------------------
1 | from huey import crontab
2 | from huey.contrib.djhuey import db_periodic_task
3 |
4 | from conreq.utils.environment import get_str_from_env
5 |
6 | from .radarr import RadarrManager
7 | from .sonarr import SonarrManager
8 |
9 | ARR_REFRESH_INTERNAL = get_str_from_env("ARR_REFRESH_INTERNAL", "*/1")
10 |
11 |
12 | @db_periodic_task(crontab(minute=ARR_REFRESH_INTERNAL, strict=True))
13 | def refresh_radarr_library():
14 | """Checks Radarr for new entries."""
15 | RadarrManager().refresh_library()
16 |
17 |
18 | @db_periodic_task(crontab(minute=ARR_REFRESH_INTERNAL, strict=True))
19 | def refresh_sonarr_library():
20 | """Checks Sonarr for new entries."""
21 | SonarrManager().refresh_library()
22 |
--------------------------------------------------------------------------------
/conreq/core/base/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/__init__.py
--------------------------------------------------------------------------------
/conreq/core/base/apps.py:
--------------------------------------------------------------------------------
1 | from sqlite3 import Connection
2 |
3 | from django.apps import AppConfig
4 | from django.db.backends.signals import connection_created
5 |
6 |
7 | class BaseConfig(AppConfig):
8 | name = "conreq.core.base"
9 |
10 |
11 | # pylint: disable=unused-argument
12 | @connection_created.connect
13 | def sqlite_connect(sender, connection: Connection, **kwargs):
14 | """Enable integrity constraint with sqlite."""
15 | if connection.vendor == "sqlite":
16 | cursor = connection.cursor()
17 | cursor.execute("PRAGMA journal_mode = WAL;")
18 | cursor.execute("PRAGMA synchronous = NORMAL;")
19 | cursor.execute("PRAGMA temp_store = MEMORY;")
20 | cursor.execute("PRAGMA foreign_keys = ON;")
21 |
22 |
23 | @connection_created.disconnect
24 | def sqlite_disconnect(sender, connection: Connection, **kwargs):
25 | """Enable integrity constraint with sqlite."""
26 | if connection.vendor == "sqlite":
27 | cursor = connection.cursor()
28 | cursor.execute("PRAGMA analysis_limit = 400;")
29 | cursor.execute("PRAGMA optimize;")
30 |
--------------------------------------------------------------------------------
/conreq/core/base/fields.py:
--------------------------------------------------------------------------------
1 | from django.db.models import URLField
2 |
3 | from . import forms, validators
4 |
5 |
6 | class ExtendedURLField(URLField):
7 | """URL field that supports hostnames (ex. https://sonarr:8000)"""
8 | default_validators = [validators.ExtendedURLValidator()]
9 |
10 | def formfield(self, **kwargs):
11 | # As with CharField, this will cause URL validation to be performed
12 | # twice.
13 | return super().formfield(
14 | **{
15 | "form_class": forms.ExtendedURLField,
16 | **kwargs,
17 | }
18 | )
19 |
--------------------------------------------------------------------------------
/conreq/core/base/forms.py:
--------------------------------------------------------------------------------
1 | from django import forms
2 | from django.contrib.auth import get_user_model
3 | from django.contrib.auth.forms import UserCreationForm
4 | from django.forms import URLField
5 |
6 | from . import validators
7 |
8 |
9 | class ExtendedURLField(URLField):
10 | """URL field that supports hostnames (ex. https://sonarr:8000)"""
11 |
12 | default_validators = [validators.ExtendedURLValidator()]
13 |
14 |
15 | class InitializationForm(UserCreationForm):
16 | sonarr_url = ExtendedURLField(max_length=255, required=False)
17 | sonarr_api_key = forms.CharField(max_length=255, required=False)
18 | radarr_url = ExtendedURLField(max_length=255, required=False)
19 | radarr_api_key = forms.CharField(max_length=255, required=False)
20 |
21 | class Meta:
22 | model = get_user_model()
23 | fields = ("username", "email", "password1", "password2")
24 |
--------------------------------------------------------------------------------
/conreq/core/base/helpers.py:
--------------------------------------------------------------------------------
1 | """Helpers for Base"""
2 |
3 |
4 | def initialize_conreq(conreq_config, form):
5 | """Sets up the initial database values during Conreq's first run sequence."""
6 | # Obtain the sonarr/radarr parameters
7 | conreq_config.sonarr_url = form.cleaned_data.get("sonarr_url")
8 | conreq_config.sonarr_api_key = form.cleaned_data.get("sonarr_api_key")
9 | conreq_config.radarr_url = form.cleaned_data.get("radarr_url")
10 | conreq_config.radarr_api_key = form.cleaned_data.get("radarr_api_key")
11 |
12 | # Enable Sonarr if URL and API key is configured
13 | if conreq_config.sonarr_url and conreq_config.sonarr_api_key:
14 | conreq_config.sonarr_enabled = True
15 |
16 | # Enable Radarr if URL and API key is configured
17 | if conreq_config.radarr_url and conreq_config.radarr_api_key:
18 | conreq_config.radarr_enabled = True
19 |
20 | # Remember that the database has been initialized
21 | conreq_config.conreq_initialized = True
22 | conreq_config.save()
23 |
--------------------------------------------------------------------------------
/conreq/core/base/management/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/management/__init__.py
--------------------------------------------------------------------------------
/conreq/core/base/management/commands/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/management/commands/__init__.py
--------------------------------------------------------------------------------
/conreq/core/base/management/commands/start_conreq_app.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from django.conf import settings
4 | from django.core.management import call_command
5 | from django.core.management.base import BaseCommand
6 |
7 | APPS_DIR = getattr(settings, "APPS_DIR")
8 | BASE_DIR = getattr(settings, "BASE_DIR")
9 | APP_TEMPLATE_DIR = os.path.join(BASE_DIR, "conreq", "app_template")
10 |
11 |
12 | class Command(BaseCommand):
13 | help = "Creates all files needed to start a new Conreq app."
14 |
15 | def handle(self, *args, **options):
16 | call_command(
17 | "startapp",
18 | "--template=" + APP_TEMPLATE_DIR,
19 | options["name"],
20 | APPS_DIR,
21 | )
22 |
23 | def add_arguments(self, parser):
24 | parser.add_argument(
25 | "name",
26 | help="Name of the new app.",
27 | )
28 |
--------------------------------------------------------------------------------
/conreq/core/base/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/migrations/__init__.py
--------------------------------------------------------------------------------
/conreq/core/base/static/css/dark.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/css/dark.css
--------------------------------------------------------------------------------
/conreq/core/base/static/css/initialization.css:
--------------------------------------------------------------------------------
1 | /* Input boxes that gets an error on validation */
2 | input.invalid {
3 | background-color: #ffdddd;
4 | }
5 |
6 | /* The active form tab */
7 | .tab {
8 | display: none;
9 | flex-direction: column;
10 | width: 100%;
11 | align-items: center;
12 | justify-content: space-evenly;
13 | }
14 |
15 | /* Current step indicator */
16 | .step {
17 | height: 15px;
18 | width: 15px;
19 | margin: 0 2px;
20 | background-color: #bbbbbb;
21 | border: none;
22 | border-radius: 50%;
23 | display: inline-block;
24 | opacity: 0.3;
25 | }
26 |
27 | .step.active {
28 | background: var(--accent-color);
29 | opacity: 1;
30 | }
31 |
32 | .step.finish {
33 | background: var(--accent-color);
34 | opacity: 0.5;
35 | }
36 |
37 | /* Navigation controls */
38 | #prevBtn {
39 | margin-right: 20px;
40 | }
41 |
42 | #box-nav-container {
43 | display: flex;
44 | width: 90%;
45 | justify-content: space-between;
46 | }
47 |
--------------------------------------------------------------------------------
/conreq/core/base/static/css/issues.css:
--------------------------------------------------------------------------------
1 | .issue-container {
2 | padding: 15px;
3 | border-radius: 8px;
4 | background: #252525;
5 | color: rgba(255, 255, 255, 0.75);
6 | font-weight: 300;
7 | line-height: 18px;
8 | height: auto;
9 | overflow: hidden;
10 | width: 300px;
11 | }
12 |
13 | .issue-container .content-type-icon {
14 | position: absolute;
15 | top: 10px;
16 | right: 10px;
17 | }
18 |
19 | .issue-container .issue-manage-icons {
20 | position: absolute;
21 | bottom: 10px;
22 | right: 10px;
23 | }
24 |
25 | .issue-container .issue-manage-icons .fas {
26 | transition: 0.3s color ease;
27 | margin-left: 10px;
28 | }
29 |
30 | .issue-container .issue-manage-icons .fas:hover {
31 | color: #fff;
32 | }
33 |
34 | .issue-container .title {
35 | font-weight: 700;
36 | }
37 |
38 | .issue-container .category:not(:last-child) {
39 | margin-bottom: 10px;
40 | }
41 |
42 | .issue-container .category.content-name {
43 | padding-right: 25px;
44 | }
45 |
46 | .issue-container .category.content-name a {
47 | display: block;
48 | }
49 |
--------------------------------------------------------------------------------
/conreq/core/base/static/css/login.css:
--------------------------------------------------------------------------------
1 | .sign-in-form {
2 | margin-top: 35px;
3 | }
4 |
--------------------------------------------------------------------------------
/conreq/core/base/static/css/navbar.css:
--------------------------------------------------------------------------------
1 | .navbar {
2 | background: var(--navbar-bg);
3 | height: var(--navbar-height);
4 | box-shadow: var(--box-shadow);
5 | padding-left: 20px;
6 | padding-right: 20px;
7 | z-index: 3;
8 | display: none;
9 | }
10 |
11 | .navbar-dark .navbar-brand {
12 | margin-left: 20px;
13 | margin-right: 0;
14 | color: rgba(255, 255, 255, 0.5);
15 | font-weight: 500;
16 | font-size: 16px;
17 | }
18 |
19 | .navbar .navbar-toggler {
20 | display: flex;
21 | }
22 |
23 | .navbar-toggler-icon {
24 | font-size: 16px;
25 | }
26 |
27 | .searchbar {
28 | position: relative;
29 | height: 40px;
30 | margin: auto;
31 | margin-bottom: 30px;
32 | width: var(--searchbar-width);
33 | background: rgb(0 0 0 / 0.45);
34 | border-radius: 15px;
35 | transition: background 0.4s ease, color 0.4s ease;
36 | color: rgba(255, 255, 255, 0.3);
37 | overflow: hidden;
38 | display: flex;
39 | }
40 |
41 | .viewport-container .searchbar,
42 | .viewport-container-top .searchbar {
43 | box-shadow: var(--poster-box-shadow);
44 | }
45 |
46 | .searchbar:focus-within {
47 | background: #fff;
48 | color: #252525;
49 | }
50 |
51 | .searchbar input {
52 | box-sizing: border-box;
53 | height: 100%;
54 | max-width: 100%;
55 | background: none;
56 | width: calc(100% - 40px);
57 | color: inherit;
58 | border: none;
59 | font-size: var(--primary-font-size);
60 | font-weight: 500;
61 | padding-left: 15px;
62 | outline: none !important;
63 | }
64 |
65 | .searchbar .fa-search {
66 | top: 0px;
67 | right: 0px;
68 | margin-right: 15px;
69 | width: calc(var(--navbar-height) * 0.3);
70 | color: inherit;
71 | margin: 0 auto;
72 | display: flex;
73 | justify-content: center;
74 | align-items: center;
75 | }
76 |
77 | button {
78 | transition: background 0.3s ease;
79 | }
80 |
81 | button:focus {
82 | outline: none;
83 | background: rgb(255 255 255 / 0.04);
84 | }
85 |
--------------------------------------------------------------------------------
/conreq/core/base/static/css/server_settings.css:
--------------------------------------------------------------------------------
1 | .settings-group-title {
2 | font-size: 21px;
3 | line-height: 1.5;
4 | }
5 |
6 | .viewport.settings {
7 | width: 100%;
8 | max-width: calc(
9 | 1920px - var(--sidebar-width) - var(--viewport-total-padding)
10 | );
11 | }
12 |
13 | .settings-group {
14 | width: 100%;
15 | margin-bottom: 30px;
16 | }
17 |
18 | .settings-input-group {
19 | display: grid;
20 | flex-direction: column;
21 | margin: 0;
22 | grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr);
23 | -moz-column-gap: 20px;
24 | column-gap: 50px;
25 | }
26 |
27 | .settings-item-group {
28 | display: flex;
29 | flex-direction: column;
30 | justify-content: center;
31 | min-height: 70px;
32 | }
33 |
34 | .text-input-title {
35 | font-weight: 500;
36 | line-height: 1.5;
37 | }
38 |
39 | .settings-item.text-display-only {
40 | display: flex;
41 | align-items: center;
42 | height: 100%;
43 | padding-left: 15px;
44 | padding-right: 15px;
45 | font-size: 16px;
46 | }
47 |
48 | .settings-item.text-display-only .settings-item-text {
49 | width: calc(100% - 15px);
50 | }
51 |
52 | .settings-item .fas {
53 | margin-left: 15px;
54 | font-size: 18px;
55 | }
56 |
57 | .settings-item .fas:first {
58 | margin-left: auto;
59 | }
60 |
61 | input[type="text"]:not(.content-search) {
62 | width: 100%;
63 | }
64 |
65 | .settings-item.toggler label {
66 | font-weight: 500;
67 | }
68 |
69 | .check-update-btn {
70 | align-self: center;
71 | width: auto;
72 | margin: auto;
73 | }
74 |
75 | .settings-item-details.info {
76 | word-wrap: break-word;
77 | }
78 |
79 | .settings-item-group.toggler {
80 | min-height: 45px;
81 | }
82 |
--------------------------------------------------------------------------------
/conreq/core/base/static/css/simple_posters.css:
--------------------------------------------------------------------------------
1 | .viewport .poster-container {
2 | height: var(--poster-height);
3 | }
4 |
5 | .viewport .poster-container .fa-angle-down {
6 | padding-top: 0px;
7 | color: #000000;
8 | background: #e4e4e4;
9 | -webkit-filter: drop-shadow(0 0 6px #000000);
10 | filter: drop-shadow(0 0 6px #000000);
11 | border-radius: 20px;
12 | width: 20px;
13 | height: 20px;
14 | left: 50%;
15 | bottom: 3px;
16 | transform: translate(-50%, 0%);
17 | line-height: 1.15;
18 | opacity: 0.4;
19 | transition: color 0.3s ease, background 0.3s ease, opacity 0.3s ease;
20 | }
21 |
22 | .viewport .poster-container:hover .fa-angle-down {
23 | opacity: 1;
24 | }
25 |
26 | .viewport .poster-container .fa-angle-down:hover {
27 | color: var(--accent-color);
28 | background: #ffffff;
29 | }
30 |
31 | .viewport .poster-container > a > .requested-by {
32 | top: calc(var(--poster-height) - 55px);
33 | left: 5px;
34 | right: unset;
35 | opacity: 1;
36 | }
37 |
38 | .viewport .poster-container > a > .requested-by {
39 | max-width: calc(100% - 10px);
40 | }
41 |
42 | .viewport .poster-container .poster-description-container {
43 | opacity: 0.85;
44 | position: absolute;
45 | top: -2px;
46 | left: -2px;
47 | width: calc(var(--poster-width) + 4px);
48 | pointer-events: none;
49 | background: linear-gradient(180deg, black, transparent);
50 | border: none;
51 | transition: opacity 0.6s ease;
52 | height: -webkit-fit-content;
53 | height: -moz-fit-content;
54 | height: fit-content;
55 | padding-top: 2px;
56 | padding-bottom: 25px;
57 | color: #d8d8d8;
58 | text-shadow: -2px -2px 6px #000, 2px -2px 6px #000, -2px 2px 6px #000,
59 | 2px 2px 6px #000;
60 | }
61 |
62 | .availablity-dot {
63 | margin: 8px 7px;
64 | }
65 |
66 | .viewport .poster-container:hover .poster-description-container {
67 | opacity: 1;
68 | }
69 |
70 | .poster-container.person-roles .poster-description,
71 | .poster-container.cast .poster-description {
72 | color: inherit;
73 | font-weight: 400;
74 | }
75 |
76 | .poster-container.tv .poster-description,
77 | .poster-container.movie .poster-description {
78 | display: none;
79 | }
80 |
81 | .viewport .poster-container .poster {
82 | transform: scale(1.08);
83 | }
84 |
85 | .viewport .poster-container .poster:hover {
86 | transform: none;
87 | }
88 |
89 | .viewport .poster-container > a > .content-type-icon {
90 | line-height: 1;
91 | top: unset;
92 | bottom: 5px;
93 | left: 5px;
94 | }
95 |
96 | .viewport .poster-container .description-tint {
97 | display: none;
98 | }
99 |
--------------------------------------------------------------------------------
/conreq/core/base/static/css/viewport.css:
--------------------------------------------------------------------------------
1 | .viewport-container,
2 | .viewport-container-top {
3 | position: absolute;
4 | height: calc(100% - var(--navbar-height));
5 | overflow-x: hidden;
6 | overflow-y: auto;
7 | overflow-y: overlay;
8 | width: calc(100vw - var(--viewport-left));
9 | padding: var(--viewport-padding);
10 | padding-bottom: 0;
11 | display: inline-block;
12 | color: rgb(255 255 255 / 0.75);
13 | }
14 |
15 | .viewport {
16 | padding-bottom: var(--viewport-padding);
17 | min-height: -webkit-fit-content;
18 | min-height: -moz-fit-content;
19 | min-height: fit-content;
20 | margin: auto;
21 | transition: opacity 1.5s ease;
22 | }
23 |
24 | .empty-viewport {
25 | text-align: center;
26 | min-width: -webkit-fit-content;
27 | min-width: -moz-fit-content;
28 | min-width: fit-content;
29 | width: 30%;
30 | max-width: 100%;
31 | margin: auto;
32 | margin-top: 10px;
33 | padding: 40px;
34 | border-radius: 6px;
35 | box-shadow: var(--box-shadow);
36 | line-height: 1.5;
37 | }
38 |
39 | .viewport-container > .loading-animation-container,
40 | .viewport-container-top > .loading-animation-container {
41 | display: flex;
42 | height: 100%;
43 | width: 100%;
44 | }
45 |
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/android-chrome-192x192.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/android-chrome-512x512.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/apple-touch-icon-114x114-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/apple-touch-icon-114x114-precomposed.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/apple-touch-icon-114x114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/apple-touch-icon-114x114.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/apple-touch-icon-120x120-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/apple-touch-icon-120x120-precomposed.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/apple-touch-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/apple-touch-icon-120x120.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/apple-touch-icon-144x144-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/apple-touch-icon-144x144-precomposed.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/apple-touch-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/apple-touch-icon-144x144.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/apple-touch-icon-152x152-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/apple-touch-icon-152x152-precomposed.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/apple-touch-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/apple-touch-icon-152x152.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/apple-touch-icon-180x180-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/apple-touch-icon-180x180-precomposed.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/apple-touch-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/apple-touch-icon-180x180.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/apple-touch-icon-57x57-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/apple-touch-icon-57x57-precomposed.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/apple-touch-icon-57x57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/apple-touch-icon-57x57.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/apple-touch-icon-60x60-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/apple-touch-icon-60x60-precomposed.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/apple-touch-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/apple-touch-icon-60x60.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/apple-touch-icon-72x72-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/apple-touch-icon-72x72-precomposed.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/apple-touch-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/apple-touch-icon-72x72.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/apple-touch-icon-76x76-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/apple-touch-icon-76x76-precomposed.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/apple-touch-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/apple-touch-icon-76x76.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/apple-touch-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/apple-touch-icon-precomposed.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/apple-touch-icon.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | #31b58f
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/favicon-16x16.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/favicon-32x32.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/favicon.ico
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/maskable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/maskable.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/mstile-150x150.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/mstile-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/mstile-310x310.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/mstile-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/mstile-70x70.png
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "",
3 | "short_name": "",
4 | "icons": [
5 | {
6 | "src": "/static/icons/android-chrome-192x192.png?v=A053y77goM",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "/static/icons/android-chrome-512x512.png?v=A053y77goM",
12 | "sizes": "512x512",
13 | "type": "image/png"
14 | }
15 | ],
16 | "theme_color": "#04110d",
17 | "background_color": "#04110d",
18 | "display": "standalone"
19 | }
20 |
--------------------------------------------------------------------------------
/conreq/core/base/static/icons/standard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/icons/standard.png
--------------------------------------------------------------------------------
/conreq/core/base/static/images/conreq_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/images/conreq_logo.png
--------------------------------------------------------------------------------
/conreq/core/base/static/images/conreq_logo_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/images/conreq_logo_dark.png
--------------------------------------------------------------------------------
/conreq/core/base/static/images/person_placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/images/person_placeholder.png
--------------------------------------------------------------------------------
/conreq/core/base/static/images/poster_placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/images/poster_placeholder.png
--------------------------------------------------------------------------------
/conreq/core/base/static/images/transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/static/images/transparent.png
--------------------------------------------------------------------------------
/conreq/core/base/static/js/modal.js:
--------------------------------------------------------------------------------
1 | let modal_loaded = false;
2 |
3 | // Fetches a modal via AJAX
4 | var generate_modal = async function (modal_url) {
5 | let modal_dialog = $("#modal-dialog");
6 | // Fetch the series modal
7 | modal_loaded = false;
8 | get_url(modal_url, async function (modal_html) {
9 | // Save that the modal was successfully loaded
10 | modal_loaded = true;
11 |
12 | // Place the new HTML on the page
13 | modal_dialog[0].innerHTML = DOMPurify.sanitize(modal_html);
14 |
15 | // Show the new content
16 | $("#modal-container .loading-animation").hide();
17 | $("#modal-content").show();
18 | $("#modal-container").modal("show");
19 |
20 | // Add click events
21 | request_btn_click_event();
22 | content_modal_click_event();
23 | modal_select_all_btn_click_event();
24 | modal_expand_btn_click_event();
25 | row_title_click_event();
26 | row_checkbox_click_event();
27 | row_suboption_title_click_event();
28 | row_suboption_checkbox_click_event();
29 | create_report_modal_click_event();
30 | report_btn_click_event();
31 | simple_filter_btn_click_event();
32 | modal_poster_popup_click_event();
33 | delete_user_btn_click_event();
34 | save_user_btn_click_event();
35 | }).fail(async function () {
36 | // Server couldn't fetch the modal
37 | if (http_request.statusText != "abort") {
38 | conreq_no_response_toast_message();
39 | }
40 | $("#modal-container").modal("hide");
41 | });
42 |
43 | // If the modal is taking too long to load, show a loading animation
44 | setTimeout(async function () {
45 | if (!modal_loaded) {
46 | // Show the loading icon
47 | $("#modal-content").hide();
48 | $("#modal-container").modal("show");
49 | $("#modal-container .loading-animation").show();
50 | }
51 | }, 300);
52 | };
53 |
--------------------------------------------------------------------------------
/conreq/core/base/static/js/sidebar.js:
--------------------------------------------------------------------------------
1 | $(document).ready(async function () {
2 | $(".sidebar").trigger("prepare");
3 | new SimpleBar($("#sidebar")[0]);
4 | $(".sidebar").trigger("loaded");
5 | });
6 |
--------------------------------------------------------------------------------
/conreq/core/base/static/js/sign_up.js:
--------------------------------------------------------------------------------
1 | document.querySelector("form").action =
2 | document.querySelector("form").action + window.location.search;
3 |
--------------------------------------------------------------------------------
/conreq/core/base/tasks.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sqlite3
3 |
4 | from django.conf import settings
5 | from django.db import connection
6 | from huey import crontab
7 | from huey.contrib.djhuey import db_periodic_task
8 |
9 | from conreq.utils.environment import get_database_type
10 |
11 | DB_ENGINE = get_database_type()
12 | HUEY_FILENAME = getattr(settings, "HUEY_FILENAME")
13 |
14 |
15 | @db_periodic_task(crontab(minute="0", hour="0", strict=True))
16 | def vacuum_huey_sqlite_db():
17 | """Periodically preforms a SQLITE vacuum on the background task database."""
18 | with sqlite3.connect(HUEY_FILENAME) as cursor:
19 | cursor.execute(
20 | # Only keep the 1000 latest tasks
21 | """DELETE FROM task
22 | WHERE id NOT IN (
23 | SELECT id
24 | FROM (
25 | SELECT id
26 | FROM task
27 | ORDER BY id DESC
28 | LIMIT 1000
29 | ) foo
30 | );
31 | """
32 | )
33 | with sqlite3.connect(HUEY_FILENAME) as cursor:
34 | cursor.execute("VACUUM")
35 |
36 |
37 | if DB_ENGINE == "SQLITE3":
38 |
39 | @db_periodic_task(crontab(minute="0", hour="0", strict=True))
40 | def vacuum_conreq_sqlite_db():
41 | """Periodically performs any cleanup tasks needed for the default database."""
42 | with connection.cursor() as cursor:
43 | cursor.execute("VACUUM")
44 |
--------------------------------------------------------------------------------
/conreq/core/base/templates/primary/base_app.html:
--------------------------------------------------------------------------------
1 | {% load solo_tags %}
2 | {% get_solo 'server_settings.ConreqConfig' as server_settings %}
3 | {% load static compress %}
4 | {% load static %}
5 | {% load conreq_tags %}
6 |
7 |
8 |
9 |
10 | {% include "primary/head_content.html" %}
11 |
12 |
13 |
14 |
15 |
16 | {% include "primary/navbar.html" %}
17 | {% include "primary/sidebar.html" %}
18 | {% include "modal/default.html" %}
19 |
20 | {% include "primary/loading_animation_container.html" %}
21 |
22 |
23 | {% include "primary/loading_animation_container.html" %}
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/conreq/core/base/templates/primary/head_content_slim.html:
--------------------------------------------------------------------------------
1 | {% load static compress %}
2 | {% load solo_tags %}
3 | {% get_solo 'server_settings.ConreqConfig' as server_settings %}
4 | {% load static %}
5 | {% load conreq_tags %}
6 |
7 |
8 | {% app_name %}
9 |
10 |
11 |
12 |
13 | {% include "primary/icons.html" %}
14 |
15 |
16 |
17 |
18 |
19 |
21 |
22 |
23 |
25 |
27 |
28 |
29 |
32 |
33 | {% compress css %}
34 |
35 |
36 |
37 |
38 |
39 |
40 | {% endcompress %}
41 |
42 | {% compress js %}
43 |
44 |
45 |
46 |
47 |
48 | {% endcompress %}
--------------------------------------------------------------------------------
/conreq/core/base/templates/primary/icons.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/conreq/core/base/templates/primary/loading_animation.html:
--------------------------------------------------------------------------------
1 |
2 | Loading...
3 |
--------------------------------------------------------------------------------
/conreq/core/base/templates/primary/loading_animation_container.html:
--------------------------------------------------------------------------------
1 |
2 | {% include "primary/loading_animation.html" %}
3 |
--------------------------------------------------------------------------------
/conreq/core/base/templates/primary/navbar.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% load conreq_tags %}
3 |
4 |
5 |
6 |
7 |
8 |
9 | {% app_name %}
10 |
11 |
--------------------------------------------------------------------------------
/conreq/core/base/templates/primary/searchbar.html:
--------------------------------------------------------------------------------
1 | {% load conreq_tags %}
2 |
3 |
4 |
8 |
9 |
--------------------------------------------------------------------------------
/conreq/core/base/templatetags/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/base/templatetags/__init__.py
--------------------------------------------------------------------------------
/conreq/core/base/templatetags/conreq_tags.py:
--------------------------------------------------------------------------------
1 | from django import template
2 | from django.urls import reverse
3 |
4 | from conreq.utils.environment import get_base_url, get_str_from_env
5 |
6 | register = template.Library()
7 | base_url_len = len(get_base_url())
8 | conreq_app_name = get_str_from_env("APP_NAME", "Conreq")
9 | conreq_app_description = get_str_from_env("APP_DESCRIPTION", "Content Requesting")
10 |
11 |
12 | @register.simple_tag
13 | def viewport_url(namespace):
14 | url = reverse(namespace)
15 | return "#" + url[base_url_len:]
16 |
17 |
18 | @register.simple_tag
19 | def viewport_top_url(namespace):
20 | url = reverse(namespace)
21 | return "#" + "/display" + url[base_url_len:]
22 |
23 |
24 | @register.simple_tag
25 | def app_name():
26 | return conreq_app_name
27 |
28 |
29 | @register.simple_tag
30 | def app_description():
31 | return conreq_app_description
32 |
33 |
34 | @register.filter
35 | def contains_valid_id(results):
36 | if isinstance(results, list):
37 | for result in results:
38 | if isinstance(result, dict) and result.get("conreq_valid_id"):
39 | return True
40 | return False
41 |
42 |
43 | @register.filter
44 | def email_enabled(_):
45 | """Temporary hacky shortcut to determine if email is enabled."""
46 | from django.conf import settings
47 |
48 | return settings.EMAIL_ENABLED
49 |
--------------------------------------------------------------------------------
/conreq/core/base/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 |
3 | from . import views
4 |
5 | app_name = "base"
6 |
7 | urlpatterns = [
8 | path("", views.landing, name="landing"),
9 | path("home/", views.home, name="homescreen"),
10 | ]
11 |
--------------------------------------------------------------------------------
/conreq/core/base/validators.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | from django.core.validators import URLValidator
4 | from django.utils.deconstruct import deconstructible
5 | from django.utils.regex_helper import _lazy_re_compile
6 |
7 |
8 | @deconstructible
9 | class ExtendedURLValidator(URLValidator):
10 | """URL validator that supports hostnames (ex. https://sonarr:8000)"""
11 |
12 | # pylint: disable=too-few-public-methods
13 | ul = URLValidator.ul
14 | ipv4_re = URLValidator.ipv4_re
15 | ipv6_re = URLValidator.ipv6_re
16 | hostname_re = URLValidator.hostname_re
17 | domain_re = URLValidator.domain_re
18 |
19 | tld_re = (
20 | r"\.?" # OPTIONAL dot (allows for hostnames)
21 | r"(?!-)" # can't start with a dash
22 | r"(?:[a-z" + ul + "-]{2,63}" # domain label
23 | r"|xn--[a-z0-9]{1,59})" # or punycode label
24 | r"(?
3 |
4 |
5 |
6 | {% include "primary/head_content_slim.html" %}
7 |
8 |
9 |
10 |
11 |
15 |
16 |
17 |
18 |
21 |
22 |
RESET MY PASSWORD
23 | Enter your username or email.
24 |
25 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/conreq/core/password_reset/templates/conreq/password_reset_confirm.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 |
3 |
4 |
5 |
6 | {% include "primary/head_content_slim.html" %}
7 |
8 |
9 |
10 |
11 |
15 |
16 |
17 |
18 |
21 |
22 | {% if validlink %}
23 |
PASSWORD RESET
24 |
Please enter your new password.
25 |
33 | {% else %}
34 |
INVALID PASSWORD RESET
35 |
Key used or expired.
36 |
37 | The password reset link was invalid, possibly because it has already been used. Please request a new
38 | password reset.
39 |
40 | {% endif %}
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/conreq/core/password_reset/templates/conreq/password_reset_sent.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 |
3 |
4 |
5 |
6 | {% include "primary/head_content_slim.html" %}
7 |
8 |
9 |
10 |
11 |
15 |
16 |
17 |
18 |
21 |
22 |
23 |
PASSWORD RESET SENT
24 |
Reset email has been sent.
25 |
26 | We’ve emailed you instructions for setting your password, if an account exists with the details you
27 | entered. You
28 | should receive them shortly.
29 |
30 |
31 | If you don’t receive an email, please make sure you’ve entered the correct information.
32 | Additionally, make sure to check your spam folder.
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/conreq/core/password_reset/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 |
3 | from .views import PasswordResetView, PasswordResetConfirmView, PassWordResetDoneView
4 |
5 | urlpatterns = [
6 | path("", PasswordResetView.as_view(), name="password_reset"),
7 | path("sent", PassWordResetDoneView.as_view(), name="password_reset_sent"),
8 | path(
9 | "/",
10 | PasswordResetConfirmView.as_view(),
11 | name="password_reset_confirm",
12 | ),
13 | ]
14 |
--------------------------------------------------------------------------------
/conreq/core/password_reset/views.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth import views as auth_views
2 | from django.urls import reverse_lazy
3 |
4 | from conreq.core.password_reset.forms import PasswordResetForm, SetPasswordForm
5 |
6 |
7 | class PasswordResetView(auth_views.PasswordResetView):
8 | success_url = reverse_lazy("password_reset_sent")
9 | template_name = "conreq/password_reset.html"
10 | form_class = PasswordResetForm
11 |
12 |
13 | class PassWordResetDoneView(auth_views.PasswordResetDoneView):
14 | template_name = "conreq/password_reset_sent.html"
15 |
16 |
17 | class PasswordResetConfirmView(auth_views.PasswordResetConfirmView):
18 | template_name = "conreq/password_reset_confirm.html"
19 | success_url = reverse_lazy("base:homescreen")
20 | post_reset_login = True
21 | form_class = SetPasswordForm
22 |
--------------------------------------------------------------------------------
/conreq/core/pwa/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License (MIT)
2 |
3 | Copyright (c) 2014 Scott Vitale, Silvio Luis and Contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/conreq/core/pwa/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/pwa/__init__.py
--------------------------------------------------------------------------------
/conreq/core/pwa/app_settings.py:
--------------------------------------------------------------------------------
1 | """ Settings required by django-app. """
2 | import os
3 |
4 | from django.conf import settings
5 | from django.shortcuts import resolve_url
6 | from django.urls import get_script_prefix
7 | from django.utils.functional import lazy
8 |
9 | from conreq.utils.environment import get_base_url
10 |
11 | # Lazy-evaluate URLs so including pwa.urls in root urlconf works
12 | resolve_url = lazy(resolve_url, str)
13 |
14 | # Get script prefix for apps not mounted under /
15 | _PWA_SCRIPT_PREFIX = get_script_prefix()
16 |
17 | # Path to the service worker implementation. Default implementation is empty.
18 | PWA_SERVICE_WORKER_PATH = getattr(
19 | settings,
20 | "PWA_SERVICE_WORKER_PATH",
21 | os.path.join(
22 | os.path.abspath(os.path.dirname(__file__)), "templates", "serviceworker.js"
23 | ),
24 | )
25 | # App parameters to include in manifest.json and appropriate meta tags
26 | PWA_APP_NAME = getattr(settings, "PWA_APP_NAME", "MyApp")
27 | PWA_APP_DESCRIPTION = getattr(settings, "PWA_APP_DESCRIPTION", "My Progressive Web App")
28 | PWA_APP_ROOT_URL = resolve_url(
29 | getattr(settings, "PWA_APP_ROOT_URL", _PWA_SCRIPT_PREFIX)
30 | )
31 | PWA_APP_THEME_COLOR = getattr(settings, "PWA_APP_THEME_COLOR", "#000")
32 | PWA_APP_BACKGROUND_COLOR = getattr(settings, "PWA_APP_BACKGROUND_COLOR", "#fff")
33 | PWA_APP_DISPLAY = getattr(settings, "PWA_APP_DISPLAY", "standalone")
34 | PWA_APP_SCOPE = resolve_url(getattr(settings, "PWA_APP_SCOPE", _PWA_SCRIPT_PREFIX))
35 | PWA_APP_DEBUG_MODE = getattr(settings, "PWA_APP_DEBUG_MODE", True)
36 | PWA_APP_ORIENTATION = getattr(settings, "PWA_APP_ORIENTATION", "any")
37 | PWA_APP_START_URL = resolve_url(
38 | getattr(settings, "PWA_APP_START_URL", _PWA_SCRIPT_PREFIX)
39 | )
40 | PWA_APP_FETCH_URL = resolve_url(
41 | getattr(settings, "PWA_APP_FETCH_URL", _PWA_SCRIPT_PREFIX)
42 | )
43 | PWA_APP_STATUS_BAR_COLOR = getattr(settings, "PWA_APP_STATUS_BAR_COLOR", "default")
44 | PWA_APP_ICONS = getattr(settings, "PWA_APP_ICONS", [])
45 | PWA_APP_ICONS_APPLE = getattr(settings, "PWA_APP_ICONS_APPLE", [])
46 | PWA_APP_SPLASH_SCREEN = getattr(settings, "PWA_APP_SPLASH_SCREEN", [])
47 | PWA_APP_DIR = getattr(settings, "PWA_APP_DIR", "auto")
48 | PWA_APP_LANG = getattr(settings, "PWA_APP_LANG", "en-US")
49 | PWA_BASE_URL = get_base_url()
50 |
--------------------------------------------------------------------------------
/conreq/core/pwa/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class PwaConfig(AppConfig):
5 | name = "conreq.core.pwa"
6 |
--------------------------------------------------------------------------------
/conreq/core/pwa/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/pwa/migrations/__init__.py
--------------------------------------------------------------------------------
/conreq/core/pwa/templates/manifest.json:
--------------------------------------------------------------------------------
1 | {% load pwa %}
2 | {
3 | "name": {{ PWA_APP_NAME|js }},
4 | "short_name": {{ PWA_APP_NAME|js }},
5 | "description": {{ PWA_APP_DESCRIPTION|js }},
6 | "start_url": {{ PWA_APP_START_URL|js }},
7 | "display": {{ PWA_APP_DISPLAY|js }},
8 | "scope": {{ PWA_APP_SCOPE|js }},
9 | "orientation": {{ PWA_APP_ORIENTATION|js }},
10 | "background_color": {{ PWA_APP_BACKGROUND_COLOR|js }},
11 | "theme_color": {{ PWA_APP_THEME_COLOR|js }},
12 | "status_bar": {{ PWA_APP_STATUS_BAR_COLOR|js }},
13 | "icons": {{ PWA_APP_ICONS|js }},
14 | "dir": {{ PWA_APP_DIR|js }},
15 | "lang": {{ PWA_APP_LANG|js }}
16 | }
17 |
--------------------------------------------------------------------------------
/conreq/core/pwa/templates/offline.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% load conreq_tags %}
3 |
4 |
5 |
6 |
7 | {% include "primary/head_content_slim.html" %}
8 |
9 |
10 |
11 |
12 |
16 |
17 |
18 |
19 |
Could not connect to {% app_name %}.
20 |
Check your network connection or try again later.
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/conreq/core/pwa/templates/pwa.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | {% for icon in PWA_APP_ICONS_APPLE %}
19 |
20 | {% endfor %}
21 | {% for icon in PWA_APP_ICONS %}
22 |
23 | {% endfor %}
24 |
25 |
26 | {% for splash in PWA_APP_SPLASH_SCREEN %}
27 |
28 | {% endfor %}
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/conreq/core/pwa/templates/serviceworker.js:
--------------------------------------------------------------------------------
1 | // Base Service Worker implementation. To use your own Service Worker, set the PWA_SERVICE_WORKER_PATH variable in settings.py
2 |
3 | var staticCacheName = "django-pwa-v" + new Date().getTime();
4 | var filesToCache = [
5 | "{{ base_url|escapejs }}/offline/",
6 | "{{ base_url|escapejs }}/static/css/main_slim.css",
7 | ];
8 |
9 | // Cache on install
10 | self.addEventListener("install", (event) => {
11 | this.skipWaiting();
12 | event.waitUntil(
13 | caches.open(staticCacheName).then((cache) => {
14 | return cache.addAll(filesToCache);
15 | })
16 | );
17 | });
18 |
19 | // Clear cache on activate
20 | self.addEventListener("activate", (event) => {
21 | event.waitUntil(
22 | caches.keys().then((cacheNames) => {
23 | return Promise.all(
24 | cacheNames
25 | .filter((cacheName) => cacheName.startsWith("django-pwa-"))
26 | .filter((cacheName) => cacheName !== staticCacheName)
27 | .map((cacheName) => caches.delete(cacheName))
28 | );
29 | })
30 | );
31 | });
32 |
33 | // Serve from Cache
34 | self.addEventListener("fetch", (event) => {
35 | event.respondWith(
36 | caches
37 | .match(event.request)
38 | .then((response) => {
39 | return response || fetch(event.request);
40 | })
41 | .catch(() => {
42 | return caches.match("{{ base_url|escapejs }}/offline/");
43 | })
44 | );
45 | });
46 |
--------------------------------------------------------------------------------
/conreq/core/pwa/templatetags/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/pwa/templatetags/__init__.py
--------------------------------------------------------------------------------
/conreq/core/pwa/templatetags/pwa.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | from django import template
4 | from django.core.serializers.json import DjangoJSONEncoder
5 | from django.utils.safestring import mark_safe
6 |
7 | from .. import app_settings
8 |
9 | register = template.Library()
10 |
11 |
12 | @register.filter(is_safe=True)
13 | def js(obj):
14 | """Transform a python object so it can be safely used in javascript/JSON."""
15 | return mark_safe(json.dumps(obj, cls=DjangoJSONEncoder))
16 |
17 |
18 | @register.inclusion_tag("pwa.html", takes_context=True)
19 | def progressive_web_app_meta(context):
20 | # Pass all PWA_* settings into the template
21 | return {
22 | setting_name: getattr(app_settings, setting_name)
23 | for setting_name in dir(app_settings)
24 | if setting_name.startswith("PWA_")
25 | }
26 |
--------------------------------------------------------------------------------
/conreq/core/pwa/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 |
3 | from .views import manifest, offline, service_worker
4 |
5 | app_name = "pwa"
6 | # Serve up serviceworker.js and manifest.json at the root
7 | urlpatterns = [
8 | path("serviceworker.js", service_worker, name="serviceworker"),
9 | path("manifest.json", manifest, name="manifest"),
10 | path("offline/", offline, name="offline"),
11 | ]
12 |
--------------------------------------------------------------------------------
/conreq/core/pwa/views.py:
--------------------------------------------------------------------------------
1 | from django.shortcuts import render
2 |
3 | from conreq.utils.environment import get_base_url
4 |
5 | from . import app_settings
6 |
7 | BASE_URL = get_base_url()
8 |
9 |
10 | def service_worker(request):
11 | return render(
12 | request,
13 | "serviceworker.js",
14 | {"base_url": BASE_URL},
15 | content_type="application/javascript",
16 | )
17 |
18 |
19 | def manifest(request):
20 | return render(
21 | request,
22 | "manifest.json",
23 | {
24 | setting_name: getattr(app_settings, setting_name)
25 | for setting_name in dir(app_settings)
26 | if setting_name.startswith("PWA_")
27 | },
28 | content_type="application/json",
29 | )
30 |
31 |
32 | def offline(request):
33 | return render(request, "offline.html")
34 |
--------------------------------------------------------------------------------
/conreq/core/search/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/search/__init__.py
--------------------------------------------------------------------------------
/conreq/core/search/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class SearchConfig(AppConfig):
5 | name = "conreq.core.search"
6 |
--------------------------------------------------------------------------------
/conreq/core/search/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/search/migrations/__init__.py
--------------------------------------------------------------------------------
/conreq/core/search/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 |
3 | from . import views
4 |
5 | app_name = "search"
6 | urlpatterns = [
7 | path("", views.search, name="main"),
8 | ]
9 |
--------------------------------------------------------------------------------
/conreq/core/search/views.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth.decorators import login_required
2 | from django.http import HttpResponse
3 | from django.template import loader
4 | from django.views.decorators.cache import cache_page
5 |
6 | from conreq.core.discover.helpers import set_many_availability
7 | from conreq.core.tmdb.discovery import TmdbDiscovery
8 | from conreq.core.tmdb.search import TmdbSearch
9 | from conreq.utils.debug import performance_metrics
10 |
11 |
12 | @cache_page(15)
13 | @login_required
14 | @performance_metrics()
15 | def search(request):
16 | content_discovery = TmdbDiscovery()
17 | searcher = TmdbSearch()
18 |
19 | # Get the ID from the URL
20 | query = request.GET.get("query", "")
21 | content_type = request.GET.get("content_type", None)
22 | page = int(request.GET.get("page", 1))
23 |
24 | # Determine which search method to use (tv/movie/all)
25 | if content_type == "tv":
26 | tmdb_results = searcher.television(query, page)
27 | elif content_type == "movie":
28 | tmdb_results = searcher.movie(query, page)
29 | else:
30 | tmdb_results = searcher.all(query, page)
31 |
32 | if tmdb_results:
33 | tmdb_results = tmdb_results.get("results")
34 |
35 | # Determine the availability
36 | content_discovery.determine_id_validity(tmdb_results)
37 | set_many_availability(tmdb_results)
38 |
39 | context = {
40 | "all_cards": tmdb_results,
41 | "content_type": content_type,
42 | "search_query": query,
43 | }
44 | template = loader.get_template("viewport/search.html")
45 | return HttpResponse(template.render(context, request))
46 |
--------------------------------------------------------------------------------
/conreq/core/server_settings/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/server_settings/__init__.py
--------------------------------------------------------------------------------
/conreq/core/server_settings/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | from conreq.core.server_settings.models import ConreqConfig
4 |
5 |
6 | # Register your models here.
7 | @admin.register(ConreqConfig)
8 | class ServerSettings(admin.ModelAdmin):
9 | pass
10 |
--------------------------------------------------------------------------------
/conreq/core/server_settings/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class ServerSettingsConfig(AppConfig):
5 | name = "conreq.core.server_settings"
6 |
--------------------------------------------------------------------------------
/conreq/core/server_settings/migrations/0002_auto_20210118_2004.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.5 on 2021-01-19 04:04
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('server_settings', '0001_initial'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name='conreqconfig',
15 | name='radarr_anime_folder',
16 | field=models.PositiveIntegerField(default=1),
17 | ),
18 | migrations.AlterField(
19 | model_name='conreqconfig',
20 | name='radarr_movies_folder',
21 | field=models.PositiveIntegerField(default=1),
22 | ),
23 | migrations.AlterField(
24 | model_name='conreqconfig',
25 | name='sonarr_anime_folder',
26 | field=models.PositiveIntegerField(default=1),
27 | ),
28 | migrations.AlterField(
29 | model_name='conreqconfig',
30 | name='sonarr_tv_folder',
31 | field=models.PositiveIntegerField(default=1),
32 | ),
33 | ]
34 |
--------------------------------------------------------------------------------
/conreq/core/server_settings/migrations/0003_conreqconfig_conreq_initialized.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.5 on 2021-01-19 08:18
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('server_settings', '0002_auto_20210118_2004'),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name='conreqconfig',
15 | name='conreq_initialized',
16 | field=models.BooleanField(default=False),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/conreq/core/server_settings/migrations/0005_auto_20210127_0107.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.5 on 2021-01-27 09:07
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('server_settings', '0004_auto_20210119_1742'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name='conreqconfig',
15 | name='conreq_dark_theme',
16 | field=models.BooleanField(default=True),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/conreq/core/server_settings/migrations/0006_auto_20210130_0236.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.5 on 2021-01-30 10:36
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('server_settings', '0005_auto_20210127_0107'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name='conreqconfig',
15 | name='conreq_custom_css',
16 | field=models.CharField(blank=True, default='', max_length=100),
17 | ),
18 | migrations.AlterField(
19 | model_name='conreqconfig',
20 | name='conreq_custom_js',
21 | field=models.CharField(blank=True, default='', max_length=100),
22 | ),
23 | ]
24 |
--------------------------------------------------------------------------------
/conreq/core/server_settings/migrations/0007_conreqconfig_conreq_http_header_auth.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.5 on 2021-02-02 12:20
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('server_settings', '0006_auto_20210130_0236'),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name='conreqconfig',
15 | name='conreq_http_header_auth',
16 | field=models.BooleanField(default=False),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/conreq/core/server_settings/migrations/0008_auto_20210203_0053.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.5 on 2021-02-03 08:53
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('server_settings', '0007_conreqconfig_conreq_http_header_auth'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name='conreqconfig',
15 | name='conreq_simple_posters',
16 | field=models.BooleanField(default=True),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/conreq/core/server_settings/migrations/0009_auto_20210204_1938.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.5 on 2021-02-05 03:38
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('server_settings', '0008_auto_20210203_0053'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name='conreqconfig',
15 | name='conreq_app_url',
16 | field=models.CharField(blank=True, default='', max_length=255),
17 | ),
18 | migrations.AlterField(
19 | model_name='conreqconfig',
20 | name='email_smtp_server',
21 | field=models.CharField(blank=True, default='', max_length=255),
22 | ),
23 | migrations.AlterField(
24 | model_name='conreqconfig',
25 | name='radarr_url',
26 | field=models.CharField(blank=True, default='', max_length=255),
27 | ),
28 | migrations.AlterField(
29 | model_name='conreqconfig',
30 | name='sonarr_url',
31 | field=models.CharField(blank=True, default='', max_length=255),
32 | ),
33 | ]
34 |
--------------------------------------------------------------------------------
/conreq/core/server_settings/migrations/0010_auto_20210205_2326.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.5 on 2021-02-06 07:26
2 |
3 | import conreq.core.base.fields
4 | from django.db import migrations, models
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ("server_settings", "0009_auto_20210204_1938"),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterField(
15 | model_name="conreqconfig",
16 | name="conreq_app_url",
17 | field=models.URLField(blank=True, default=""),
18 | ),
19 | migrations.AlterField(
20 | model_name="conreqconfig",
21 | name="radarr_url",
22 | field=conreq.core.base.fields.ExtendedURLField(blank=True, default=""),
23 | ),
24 | migrations.AlterField(
25 | model_name="conreqconfig",
26 | name="sonarr_url",
27 | field=conreq.core.base.fields.ExtendedURLField(blank=True, default=""),
28 | ),
29 | ]
30 |
--------------------------------------------------------------------------------
/conreq/core/server_settings/migrations/0011_auto_20210205_2343.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.5 on 2021-02-06 07:43
2 |
3 | from django.db import migrations
4 | import url_or_relative_url_field.fields
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('server_settings', '0010_auto_20210205_2326'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterField(
15 | model_name='conreqconfig',
16 | name='conreq_custom_css',
17 | field=url_or_relative_url_field.fields.URLOrRelativeURLField(blank=True, default=''),
18 | ),
19 | migrations.AlterField(
20 | model_name='conreqconfig',
21 | name='conreq_custom_js',
22 | field=url_or_relative_url_field.fields.URLOrRelativeURLField(blank=True, default=''),
23 | ),
24 | ]
25 |
--------------------------------------------------------------------------------
/conreq/core/server_settings/migrations/0012_auto_20210209_2144.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.5 on 2021-02-10 05:44
2 |
3 | from django.db import migrations, models
4 | import encrypted_fields.fields
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('server_settings', '0011_auto_20210205_2343'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterField(
15 | model_name='conreqconfig',
16 | name='conreq_api_key',
17 | field=models.CharField(blank=True, default='', max_length=255),
18 | ),
19 | migrations.AlterField(
20 | model_name='conreqconfig',
21 | name='email_password',
22 | field=encrypted_fields.fields.EncryptedCharField(blank=True, default='', max_length=255),
23 | ),
24 | migrations.AlterField(
25 | model_name='conreqconfig',
26 | name='email_username',
27 | field=encrypted_fields.fields.EncryptedCharField(blank=True, default='', max_length=255),
28 | ),
29 | migrations.AlterField(
30 | model_name='conreqconfig',
31 | name='radarr_api_key',
32 | field=models.CharField(blank=True, default='', max_length=255),
33 | ),
34 | migrations.AlterField(
35 | model_name='conreqconfig',
36 | name='sonarr_api_key',
37 | field=models.CharField(blank=True, default='', max_length=255),
38 | ),
39 | ]
40 |
--------------------------------------------------------------------------------
/conreq/core/server_settings/migrations/0013_conreqconfig_conreq_allow_tv_specials.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.7 on 2021-03-13 09:54
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('server_settings', '0012_auto_20210209_2144'),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name='conreqconfig',
15 | name='conreq_allow_tv_specials',
16 | field=models.BooleanField(default=True),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/conreq/core/server_settings/migrations/0014_auto_20210313_0231.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.7 on 2021-03-13 10:31
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('server_settings', '0013_conreqconfig_conreq_allow_tv_specials'),
10 | ]
11 |
12 | operations = [
13 | migrations.RemoveField(
14 | model_name='conreqconfig',
15 | name='conreq_app_logo',
16 | ),
17 | migrations.RemoveField(
18 | model_name='conreqconfig',
19 | name='conreq_app_url',
20 | ),
21 | migrations.RemoveField(
22 | model_name='conreqconfig',
23 | name='conreq_guest_login',
24 | ),
25 | migrations.RemoveField(
26 | model_name='conreqconfig',
27 | name='conreq_language',
28 | ),
29 | ]
30 |
--------------------------------------------------------------------------------
/conreq/core/server_settings/migrations/0015_remove_conreqconfig_conreq_app_name.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.7 on 2021-03-21 09:02
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('server_settings', '0014_auto_20210313_0231'),
10 | ]
11 |
12 | operations = [
13 | migrations.RemoveField(
14 | model_name='conreqconfig',
15 | name='conreq_app_name',
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/conreq/core/server_settings/migrations/0016_alter_conreqconfig_id.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2 on 2021-04-13 05:11
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('server_settings', '0015_remove_conreqconfig_conreq_app_name'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name='conreqconfig',
15 | name='id',
16 | field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/conreq/core/server_settings/migrations/0017_remove_conreqconfig_conreq_dark_theme.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2 on 2021-04-26 04:01
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('server_settings', '0016_alter_conreqconfig_id'),
10 | ]
11 |
12 | operations = [
13 | migrations.RemoveField(
14 | model_name='conreqconfig',
15 | name='conreq_dark_theme',
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/conreq/core/server_settings/migrations/0018_auto_20210428_2039.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2 on 2021-04-29 03:39
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('server_settings', '0017_remove_conreqconfig_conreq_dark_theme'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name='conreqconfig',
15 | name='radarr_anime_folder',
16 | field=models.PositiveIntegerField(default=0),
17 | ),
18 | migrations.AlterField(
19 | model_name='conreqconfig',
20 | name='radarr_anime_quality_profile',
21 | field=models.PositiveIntegerField(default=0),
22 | ),
23 | migrations.AlterField(
24 | model_name='conreqconfig',
25 | name='radarr_movies_folder',
26 | field=models.PositiveIntegerField(default=0),
27 | ),
28 | migrations.AlterField(
29 | model_name='conreqconfig',
30 | name='radarr_movies_quality_profile',
31 | field=models.PositiveIntegerField(default=0),
32 | ),
33 | migrations.AlterField(
34 | model_name='conreqconfig',
35 | name='sonarr_anime_folder',
36 | field=models.PositiveIntegerField(default=0),
37 | ),
38 | migrations.AlterField(
39 | model_name='conreqconfig',
40 | name='sonarr_anime_quality_profile',
41 | field=models.PositiveIntegerField(default=0),
42 | ),
43 | migrations.AlterField(
44 | model_name='conreqconfig',
45 | name='sonarr_tv_folder',
46 | field=models.PositiveIntegerField(default=0),
47 | ),
48 | migrations.AlterField(
49 | model_name='conreqconfig',
50 | name='sonarr_tv_quality_profile',
51 | field=models.PositiveIntegerField(default=0),
52 | ),
53 | ]
54 |
--------------------------------------------------------------------------------
/conreq/core/server_settings/migrations/0019_remove_conreqconfig_conreq_api_key.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.2 on 2021-05-10 02:32
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('server_settings', '0018_auto_20210428_2039'),
10 | ]
11 |
12 | operations = [
13 | migrations.RemoveField(
14 | model_name='conreqconfig',
15 | name='conreq_api_key',
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/conreq/core/server_settings/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/server_settings/migrations/__init__.py
--------------------------------------------------------------------------------
/conreq/core/server_settings/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 |
3 | from . import views
4 |
5 | app_name = "server_settings"
6 | urlpatterns = [
7 | path("", views.server_settings, name="main"),
8 | path("sonarr_settings", views.sonarr_settings, name="sonarr_settings"),
9 | path("radarr_settings", views.radarr_settings, name="radarr_settings"),
10 | path("update_settings", views.update_settings, name="update_settings"),
11 | ]
12 |
--------------------------------------------------------------------------------
/conreq/core/sign_up/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/sign_up/__init__.py
--------------------------------------------------------------------------------
/conreq/core/sign_up/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class SignUpConfig(AppConfig):
5 | name = "conreq.core.sign_up"
6 |
--------------------------------------------------------------------------------
/conreq/core/sign_up/forms.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth import get_user_model
2 | from django.contrib.auth.forms import UserCreationForm
3 |
4 |
5 | class UserForm(UserCreationForm):
6 | class Meta:
7 | model = get_user_model()
8 | fields = ("username", "email", "password1", "password2")
9 |
--------------------------------------------------------------------------------
/conreq/core/sign_up/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/sign_up/migrations/__init__.py
--------------------------------------------------------------------------------
/conreq/core/sign_up/templates/modal/default.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {% include "primary/loading_animation.html" %}
4 |
5 |
--------------------------------------------------------------------------------
/conreq/core/sign_up/templates/registration/sign_in.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% load conreq_tags %}
3 |
4 |
5 |
6 |
7 | {% include "primary/head_content_slim.html" %}
8 |
9 |
10 |
11 |
12 |
16 |
17 |
18 |
19 |
22 |
23 |
37 |
38 | {% if ""|email_enabled %}
39 |
42 | {% endif %}
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/conreq/core/sign_up/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 |
3 | from . import views
4 |
5 | app_name = "sign_up"
6 | urlpatterns = [
7 | path("", views.invite, name="invite_code"),
8 | path(
9 | "generate_invite_code/", views.generate_invite_code, name="generate_invite_code"
10 | ),
11 | ]
12 |
--------------------------------------------------------------------------------
/conreq/core/tmdb/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/tmdb/__init__.py
--------------------------------------------------------------------------------
/conreq/core/tmdb/templates/cards/artwork.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 |
--------------------------------------------------------------------------------
/conreq/core/tmdb/templates/cards/casted.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% load conreq_tags %}
3 |
4 |
5 |
6 |
7 |
8 | {% if card.requested_by and user.is_staff %}
9 |
10 | {{ card.requested_by }}
11 |
12 | {% endif %}
13 |
14 |
15 | {% if card.content_type == "tv" %}
16 |
17 | {% elif card.content_type == "movie" %}
18 |
19 | {% endif %}
20 |
21 |
22 |
23 | {% if card.poster_path %}
24 |
27 | {% else %}
28 |
30 | {% endif %}
31 |
32 |
33 |
34 |
35 |
38 |
39 |
40 |
41 |
42 |
{% firstof card.name card.title "Unknown" %}
43 | {% if card.availability == "Available" %}
44 |
45 | {% elif card.availability == "Partial" %}
46 |
47 | {% else %}
48 |
49 | {% endif %}
50 |
{% firstof card.character card.job card.department "Unknown Role"%}
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/conreq/core/tmdb/templates/cards/person.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% load conreq_tags %}
3 |
--------------------------------------------------------------------------------
/conreq/core/tmdb/templates/cards/poster.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% load conreq_tags %}
3 |
4 |
5 |
6 |
7 |
8 | {% if card.requested_by and user.is_staff %}
9 |
10 | {{ card.requested_by }}
11 |
12 | {% endif %}
13 |
14 |
15 | {% if card.content_type == "tv" %}
16 |
17 | {% elif card.content_type == "movie" %}
18 |
19 | {% endif %}
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
30 |
33 |
34 |
35 |
36 |
37 |
{% firstof card.name card.title "Unknown" %}
38 | {% if card.availability == "Available" %}
39 |
40 | {% elif card.availability == "Partial" %}
41 |
42 | {% else %}
43 |
44 | {% endif %}
45 |
{{card.overview}}
46 |
47 |
48 |
--------------------------------------------------------------------------------
/conreq/core/tmdb/templates/cards/review.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
"
5 | {{review.content}}
6 |
"
7 |
8 |
- {{review.author}}
9 |
10 |
--------------------------------------------------------------------------------
/conreq/core/tmdb/templates/compressed/simple_posters_css.html:
--------------------------------------------------------------------------------
1 | {% load static compress %}
2 | {% load static %}
3 | {% compress css %}
4 |
5 | {% endcompress %}
--------------------------------------------------------------------------------
/conreq/core/tmdb/templates/dropdown/item.html:
--------------------------------------------------------------------------------
1 | {{ dropdown_item.label }}
--------------------------------------------------------------------------------
/conreq/core/tmdb/templates/modal/discover_filter_advanced.html:
--------------------------------------------------------------------------------
1 | {% include "primary/loading_animation.html" %}
2 |
3 |
9 |
10 |
11 |
12 |
20 |
--------------------------------------------------------------------------------
/conreq/core/tmdb/templates/modal/discover_filter_simple.html:
--------------------------------------------------------------------------------
1 | {% include "primary/loading_animation.html" %}
2 |
3 |
9 |
10 |
11 | {% if content_type == "tv" or content_type == "movie" or not content_type %}
12 |
13 |
14 |
15 |
16 |
17 | Include Anime
18 |
19 |
20 |
21 |
22 |
23 |
24 | Anime Only
25 |
26 |
27 |
28 |
29 |
30 |
31 | No Anime
32 |
33 |
34 |
35 | {% endif %}
36 |
37 |
38 |
46 |
47 |
55 |
--------------------------------------------------------------------------------
/conreq/core/tmdb/templates/modal/report_issue.html:
--------------------------------------------------------------------------------
1 | {% include "primary/loading_animation.html" %}
2 |
3 |
9 |
10 |
11 | {% for issue, resolution in issues %}
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | {{issue}}
25 |
26 |
27 |
28 | {% endfor %}
29 |
30 |
31 |
38 |
--------------------------------------------------------------------------------
/conreq/core/tmdb/templates/viewport/components/more_info_collection.html:
--------------------------------------------------------------------------------
1 | {% if collection.parts %}
2 |
3 |
{{collection.name}}
4 |
10 |
11 |
12 |
13 | {% for card in collection.parts %}
14 |
15 | {% include "cards/poster.html" %}
16 |
17 | {% endfor %}
18 |
19 |
20 |
21 | {% endif %}
--------------------------------------------------------------------------------
/conreq/core/tmdb/templates/viewport/components/more_info_recommended.html:
--------------------------------------------------------------------------------
1 | {% if recommended.results and results_contain_valid_id %}
2 |
3 |
11 |
12 |
13 | {% for card in recommended.results %}
14 | {% if card.conreq_valid_id %}
15 |
16 | {% include "cards/poster.html" %}
17 |
18 | {% endif %}
19 | {% endfor %}
20 |
21 |
22 |
23 | {% endif %}
--------------------------------------------------------------------------------
/conreq/core/tmdb/templates/viewport/discover.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% csrf_token %}
3 | {% include "primary/loading_animation_container.html" %}
4 | {% include "primary/searchbar.html" %}
5 |
6 |
7 |
--------------------------------------------------------------------------------
/conreq/core/tmdb/templates/viewport/manage_users.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% csrf_token %}
3 | {% include "primary/loading_animation_container.html" %}
4 |
5 |
6 |
7 |
8 |
9 |
10 |
User Management
11 |
14 |
15 | Invite
16 |
17 |
18 |
19 |
20 |
21 |
22 | Username
23 | Email
24 | Joined
25 | Last Seen
26 | Staff
27 |
28 |
29 |
30 |
31 | {% for account in users %}
32 |
33 | {{ account.username }}
34 | {{ account.email }}
35 | {{ account.date_joined|date:"Y-m-d @ H:i" }}
36 | {{ account.last_login|date:"Y-m-d @ H:i" }}
37 | {{ account.is_staff|yesno:"Yes,No" }}
38 |
39 |
42 |
43 |
44 |
45 |
46 | {% endfor %}
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/conreq/core/tmdb/templates/viewport/reported_issues.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% csrf_token %}
3 | {% include "primary/loading_animation_container.html" %}
4 |
5 |
6 |
--------------------------------------------------------------------------------
/conreq/core/tmdb/templates/viewport/requests.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% csrf_token %}
3 | {% include "primary/loading_animation_container.html" %}
4 |
5 |
6 |
--------------------------------------------------------------------------------
/conreq/core/tmdb/templates/viewport/search.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% load solo_tags %}
3 | {% load conreq_tags %}
4 | {% get_solo 'server_settings.ConreqConfig' as server_settings %}
5 | {% csrf_token %}
6 | {% include "primary/loading_animation_container.html" %}
7 | {% include "primary/searchbar.html" %}
8 |
10 |
11 |
--------------------------------------------------------------------------------
/conreq/core/user_requests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/user_requests/__init__.py
--------------------------------------------------------------------------------
/conreq/core/user_requests/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | from conreq.core.user_requests.models import UserRequest
4 |
5 |
6 | # Register your models here.
7 | @admin.register(UserRequest)
8 | class AllUserRequests(admin.ModelAdmin):
9 | pass
10 |
--------------------------------------------------------------------------------
/conreq/core/user_requests/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class UserRequestsConfig(AppConfig):
5 | name = "conreq.core.user_requests"
6 |
--------------------------------------------------------------------------------
/conreq/core/user_requests/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.5 on 2021-01-30 07:39
2 |
3 | from django.conf import settings
4 | from django.db import migrations, models
5 | import django.db.models.deletion
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | initial = True
11 |
12 | dependencies = [
13 | migrations.swappable_dependency(settings.AUTH_USER_MODEL),
14 | ]
15 |
16 | operations = [
17 | migrations.CreateModel(
18 | name='UserRequest',
19 | fields=[
20 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21 | ('content_id', models.CharField(max_length=30)),
22 | ('source', models.CharField(max_length=30)),
23 | ('content_type', models.CharField(max_length=30)),
24 | ('requested_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
25 | ],
26 | ),
27 | ]
28 |
--------------------------------------------------------------------------------
/conreq/core/user_requests/migrations/0002_userrequest_date_requested.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.5 on 2021-01-31 09:47
2 |
3 | from django.db import migrations, models
4 | import django.utils.timezone
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('user_requests', '0001_initial'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='userrequest',
16 | name='date_requested',
17 | field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
18 | preserve_default=False,
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/conreq/core/user_requests/migrations/0003_alter_userrequest_id.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2 on 2021-04-13 05:11
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('user_requests', '0002_userrequest_date_requested'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name='userrequest',
15 | name='id',
16 | field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/conreq/core/user_requests/migrations/0004_alter_userrequest_requested_by.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.2 on 2021-05-09 02:37
2 |
3 | from django.conf import settings
4 | from django.db import migrations, models
5 | import django.db.models.deletion
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | migrations.swappable_dependency(settings.AUTH_USER_MODEL),
12 | ('user_requests', '0003_alter_userrequest_id'),
13 | ]
14 |
15 | operations = [
16 | migrations.AlterField(
17 | model_name='userrequest',
18 | name='requested_by',
19 | field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
20 | ),
21 | ]
22 |
--------------------------------------------------------------------------------
/conreq/core/user_requests/migrations/0005_remove_userrequest_source.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.5 on 2021-07-06 06:44
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('user_requests', '0004_alter_userrequest_requested_by'),
10 | ]
11 |
12 | operations = [
13 | migrations.RemoveField(
14 | model_name='userrequest',
15 | name='source',
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/conreq/core/user_requests/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/user_requests/migrations/__init__.py
--------------------------------------------------------------------------------
/conreq/core/user_requests/models.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth import get_user_model
2 | from django.db import models
3 |
4 | User = get_user_model()
5 |
6 | # Create your models here.
7 | class UserRequest(models.Model):
8 | content_id = models.CharField(max_length=30)
9 | content_type = models.CharField(max_length=30)
10 | requested_by = models.ForeignKey(
11 | User, on_delete=models.CASCADE, default=None, null=True, blank=True
12 | )
13 | date_requested = models.DateTimeField(auto_now_add=True)
14 |
--------------------------------------------------------------------------------
/conreq/core/user_requests/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 |
3 | from . import views
4 |
5 | app_name = "user_requests"
6 | urlpatterns = [
7 | path("", views.request_content, name="request_content"),
8 | path("my_requests/", views.my_requests, name="my_requests"),
9 | path("all_requests/", views.all_requests, name="all_requests"),
10 | ]
11 |
--------------------------------------------------------------------------------
/conreq/core/websockets/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/core/websockets/__init__.py
--------------------------------------------------------------------------------
/conreq/core/websockets/consumers.py:
--------------------------------------------------------------------------------
1 | """Anything used to construct a websocket endpoint"""
2 | from channels.auth import login
3 | from channels.db import database_sync_to_async as convert_to_async
4 | from channels.generic.websocket import AsyncJsonWebsocketConsumer
5 | from django.contrib.auth.models import AnonymousUser
6 |
7 | from conreq.utils import log
8 |
9 | _logger = log.get_logger(__name__)
10 |
11 |
12 | class CommandConsumer(AsyncJsonWebsocketConsumer):
13 | """Conreq websocket communication."""
14 |
15 | # INITIAL CONNECTION
16 | async def connect(self):
17 | """When the browser attempts to connect to the server."""
18 | # Accept the connection
19 | await self.accept()
20 |
21 | # Attempt logging in the user
22 | try:
23 | # Log in the user to this session.
24 | await login(self.scope, self.scope["user"])
25 | # Save the session to the database
26 | await convert_to_async(self.scope["session"].save)()
27 | except Exception:
28 | # User could not be logged in
29 | log.handler(
30 | "Websocket login failure on initial connection!",
31 | log.ERROR,
32 | _logger,
33 | )
34 | await self.__forbidden()
35 |
36 | # RECEIVING COMMANDS
37 | async def receive_json(self, content, **kwargs):
38 | """When the browser attempts to send a message to the server."""
39 | log.handler(
40 | content,
41 | log.INFO,
42 | _logger,
43 | )
44 | # Reject users that aren't logged in
45 | if (
46 | isinstance(self.scope["user"], AnonymousUser)
47 | or not self.scope["user"].is_authenticated
48 | ):
49 | await self.__forbidden()
50 |
51 | # COMMAND RESPONSE: FORBIDDEN
52 | async def __forbidden(self):
53 | response = {"command_name": "forbidden"}
54 | await self.send_json(response)
55 |
--------------------------------------------------------------------------------
/conreq/utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/conreq/utils/__init__.py
--------------------------------------------------------------------------------
/conreq/utils/database.py:
--------------------------------------------------------------------------------
1 | def add_unique_to_db(model, **kwargs):
2 | """Adds a row to the database only if all parameters are unique."""
3 | if not model.objects.filter(**kwargs):
4 | new_request = model(**kwargs)
5 | new_request.clean_fields()
6 | new_request.save()
7 | return new_request
8 | return None
9 |
--------------------------------------------------------------------------------
/conreq/utils/debug.py:
--------------------------------------------------------------------------------
1 | """Capabilities used while in DEBUG, that turn off in production environments."""
2 | from functools import wraps
3 |
4 | from conreq.utils.environment import get_debug
5 |
6 |
7 | # pylint: disable=invalid-name,too-few-public-methods
8 | # Helper function for doing nothing
9 | def do_nothing(function=None):
10 | def decorator(view_func):
11 | @wraps(view_func)
12 | def _wrapped_view(request, *args, **kwargs):
13 | return view_func(request, *args, **kwargs)
14 |
15 | return _wrapped_view
16 |
17 | return decorator(function)
18 |
19 |
20 | # Helper class for doing nothing
21 | class DoNothing:
22 | def __call__(self, target):
23 | return target
24 |
25 |
26 | # Set functionality depending on whether we are in DEBUG=True
27 | if get_debug():
28 | from silk.profiling.profiler import silk_profile
29 |
30 | class performance_metrics(silk_profile):
31 | pass
32 |
33 |
34 | else:
35 |
36 | class performance_metrics(DoNothing):
37 | pass
38 |
--------------------------------------------------------------------------------
/conreq/utils/generic.py:
--------------------------------------------------------------------------------
1 | """Generic functions to be used anywhere. All functions only have stdlib dependencies."""
2 | import os
3 | import pkgutil
4 | from re import sub
5 |
6 |
7 | def is_key_value_in_list(
8 | key: any, value: any, search_list: list, return_item: bool = False
9 | ) -> bool:
10 | """Iterate through a list of dicts to check if a specific key/value pair exists."""
11 | if isinstance(search_list, list):
12 | for item in search_list:
13 | if item.__contains__(key) and item[key] == value:
14 | if return_item:
15 | return item
16 | return True
17 | return False
18 |
19 |
20 | def remove_duplicates_from_list(duplicate_list: list) -> list:
21 | """Returns a list that contains no duplicate values"""
22 | return list(dict.fromkeys(duplicate_list))
23 |
24 |
25 | def clean_string(string: str) -> str:
26 | """Removes non-alphanumerics from a string"""
27 | return sub(r"\W+", "", string).lower()
28 |
29 |
30 | def str_to_bool(string: str, default_value: bool = True) -> bool:
31 | """Converts a string into a boolean."""
32 | if isinstance(string, str):
33 | if string.lower() == "true" or string == "1":
34 | return True
35 | if string.lower() == "false" or string == "0":
36 | return False
37 | return default_value
38 |
39 |
40 | def str_to_int(value: str, default_value: int = 0) -> int:
41 | """Converts a string into a integer."""
42 | if isinstance(value, str) and value.isdigit():
43 | return int(value)
44 | return default_value
45 |
46 |
47 | def list_modules(path: str, prefix: str = "") -> list[str]:
48 | """Returns all modules in a path"""
49 | return [name for _, name, _ in pkgutil.iter_modules([path], prefix=prefix)]
50 |
51 |
52 | def list_modules_with(path: str, submodule_name: str, prefix: str = "") -> list[str]:
53 | """Returns a tuple of all modules containing module name and an importable path to 'example.module.urls'"""
54 | modules = list_modules(path)
55 | module_files = []
56 | for module in modules:
57 | module_path = os.path.join(path, module)
58 | if submodule_name in list_modules(module_path):
59 | urls_path = prefix + module + "." + submodule_name
60 | module_files.append((module, urls_path))
61 | return module_files
62 |
--------------------------------------------------------------------------------
/conreq/utils/log.py:
--------------------------------------------------------------------------------
1 | """Conreq Logging: Simplified logging module."""
2 | import logging
3 | from logging import Logger
4 | from traceback import format_exc
5 |
6 | # Globals
7 | DEBUG = logging.DEBUG
8 | INFO = logging.INFO
9 | WARNING = logging.WARNING
10 | ERROR = logging.ERROR
11 | CRITICAL = logging.CRITICAL
12 |
13 | # Function reference to Py Logging getLogger
14 | get_logger = logging.getLogger
15 |
16 |
17 | def handler(msg: str, level: int, logger: Logger) -> None:
18 | """Submits a message to the log handler.
19 |
20 | Args:
21 | message: A string containing a verbose log message.
22 | logger: A logger objected obtained from get_logger().
23 | level: Logging module log level (ex. logging.WARNING)
24 | """
25 | # Remove trailing and proceeding whitespace from the message
26 | message = str(msg).rstrip("\n").rstrip().lstrip("\n").lstrip()
27 |
28 | # Log within a different stream depending on severity
29 | if level == DEBUG:
30 | logger.debug(message)
31 | elif level == INFO:
32 | logger.info(message)
33 | elif level == WARNING:
34 | logger.warning(message)
35 | elif level == ERROR:
36 | logger.error(message + "\n" + format_exc())
37 | elif level == CRITICAL:
38 | logger.critical(message + "\n" + format_exc())
39 |
--------------------------------------------------------------------------------
/conreq/utils/user_apps.py:
--------------------------------------------------------------------------------
1 | import os
2 | from importlib import import_module
3 |
4 | from django.conf import settings
5 |
6 | from .generic import list_modules
7 |
8 | APPS_DIR = getattr(settings, "APPS_DIR")
9 |
10 |
11 | def list_user_apps() -> list[str]:
12 | apps_list = []
13 | user_apps = list_modules(APPS_DIR)
14 | for user_app in user_apps:
15 | package_dict = {}
16 | package_dict["name"] = user_app
17 | package_dict["modules"] = {}
18 | app_dir = os.path.join(APPS_DIR, user_app)
19 | for package in list_modules(app_dir):
20 | sub_app_dir = os.path.join(app_dir, package)
21 | if package == "settings":
22 | module = import_module(user_app + "." + package)
23 | package_dict["settings"] = [
24 | item for item in dir(module) if not item.startswith("_")
25 | ]
26 | else:
27 | package_dict["modules"][package] = []
28 | for module in list_modules(sub_app_dir):
29 | package_dict["modules"][package].append(
30 | (module, user_app + "." + package + "." + module)
31 | )
32 | apps_list.append(package_dict)
33 |
34 | return apps_list
35 |
36 |
37 | def list_user_apps_with(submodule_name: str) -> list[str]:
38 | apps_list = []
39 | user_apps = list_modules(APPS_DIR)
40 | for user_app in user_apps:
41 | app_dir = os.path.join(APPS_DIR, user_app)
42 | for package in list_modules(app_dir):
43 | sub_app_dir = os.path.join(app_dir, package)
44 | modules = list_modules(sub_app_dir)
45 | if submodule_name in modules:
46 | apps_list.append(user_app + "." + package + "." + submodule_name)
47 | return apps_list
48 |
--------------------------------------------------------------------------------
/docs/mkdocs.yml:
--------------------------------------------------------------------------------
1 | nav:
2 | - Home: index.md
3 | - Install:
4 | - Docker: install/docker.md
5 | - Windows NSSM: install/nssm.md
6 | - Configuration:
7 | - Environment Variables: configure/env_vars.md
8 | - Built-in Webserver: configure/webserver.md
9 | - Custom CSS/JS: configure/static_files.md
10 | - Organizr Authentication: configure/organizr.md
11 | - MySQL Database: configure/mysql.md
12 | - Development:
13 | - Running Conreq Manually: develop/run_conreq.md
14 | - Building the Docker: develop/build_docker.md
15 | - Creating Custom Apps: develop/creating_apps.md
16 | - Contribute:
17 | - Updating the Docs: contrib/docs.md
18 | - Create an App Store listing: contrib/apps.md
19 |
20 | theme:
21 | name: material
22 | palette:
23 | primary: teal
24 | accent: teal
25 | features:
26 | - navigation.instant
27 | - navigation.tabs
28 | - navigation.tabs.sticky
29 | - navigation.top
30 | - content.code.copy
31 | - search.highlight
32 | - navigation.sections
33 | - toc.integrate
34 |
35 | icon:
36 | repo: fontawesome/brands/github
37 |
38 | markdown_extensions:
39 | - toc:
40 | permalink: true
41 | - pymdownx.emoji:
42 | emoji_index: !!python/name:material.extensions.emoji.twemoji
43 | emoji_generator: !!python/name:material.extensions.emoji.to_svg
44 | - pymdownx.tabbed:
45 | alternate_style: true
46 | - pymdownx.highlight:
47 | linenums: true
48 | - pymdownx.superfences
49 | - pymdownx.details
50 | - pymdownx.inlinehilite
51 | - admonition
52 | - attr_list
53 | - md_in_html
54 | - pymdownx.keys
55 |
56 | plugins:
57 | - search
58 | - include-markdown
59 | - git-authors
60 | - minify:
61 | minify_html: true
62 | minify_js: true
63 | minify_css: true
64 | cache_safe: true
65 | - git-revision-date-localized:
66 | fallback_to_build_date: true
67 | - spellcheck:
68 | known_words: dictionary.txt
69 | allow_unicode: no
70 | ignore_code: yes
71 |
72 | site_name: Conreq Documentation
73 | site_author: Archmonger
74 | site_description: Conreq Web Platform
75 | repo_url: https://github.com/Archmonger/Conreq/
76 | site_url: https://archmonger.github.io/Conreq/
77 | repo_name: Archmonger/Conreq
78 | edit_uri: edit/main/docs/src/
79 | docs_dir: src
80 |
--------------------------------------------------------------------------------
/docs/src/configure/mysql.md:
--------------------------------------------------------------------------------
1 | 1. Install and run MySQL using your preferred method.
2 |
3 | 2. Create a file within your Conreq data directory create a MySQL configuration file (`mysql.cnf`). At minimum you must include the following...
4 |
5 | ```toml
6 | [client]
7 | database = conreq
8 | user = db_username
9 | password = db_password
10 | host = 192.168.86.200
11 | default-character-set = utf8
12 | ```
13 |
14 | _Take a look at MySQL's "Options Files" docs for all available parameters._
15 |
16 | 3. Set your `DB_ENGINE ` variable to `MYSQL` and your `MYSQL_CONFIG_FILE` variable to the path to your `mysql.cnf` file.
17 |
18 | _If using Unraid/Docker, add this as a Docker variable. Otherwise, search "How to set environment variables in ... Windows 10"_
19 |
--------------------------------------------------------------------------------
/docs/src/configure/organizr.md:
--------------------------------------------------------------------------------
1 | 1. Go to `Server Settings` within Conreq and enable `Organizr User Authentication`
2 |
3 | 2. Set up a `nginx` reverse proxy.
4 |
5 | _If you need help with this, join the [`organizr` Discord](https://discord.com/invite/TrNtY7N) and post in #groups._
6 |
7 | 3. In your Conreq block within `nginx`, add the following...
8 |
9 | ```nginx
10 | # Sets Conreq to be accessible by all Organizr users. Google "Organizr ServerAuth" for more details.
11 | auth_request /auth-4;
12 |
13 | # Allows Conreq to log in as an Organizr user
14 | auth_request_set $auth_user $upstream_http_x_organizr_user;
15 | proxy_set_header X-WEBAUTH-USER $auth_user;
16 |
17 | # Allows Conreq to know the email address of an Organizr user (optional)
18 | auth_request_set $auth_email $upstream_http_x_organizr_email;
19 | proxy_set_header X-WEBAUTH-EMAIL $auth_email;
20 |
21 | # Allows Conreq to automatically configure Organizr Admins and Co-Admins as Conreq staff members (optional)
22 | auth_request_set $auth_group $upstream_http_x_organizr_group;
23 | proxy_set_header X-WEBAUTH-GROUP $auth_group;
24 | ```
25 |
--------------------------------------------------------------------------------
/docs/src/configure/static_files.md:
--------------------------------------------------------------------------------
1 | Conreq can store and serve any custom files located within your data directory's "static" folder.
2 |
3 | In order to use this to serve custom CSS or JavaScript...
4 |
5 | 1. Put a CSS/JS file into `DATA_DIR/static/`
6 | 2. Restart Conreq
7 | 3. Set your Conreq "Custom CSS/JS" to link to the new content, such as `/static/my_style.css`
8 | 4. Done!
9 |
--------------------------------------------------------------------------------
/docs/src/configure/webserver.md:
--------------------------------------------------------------------------------
1 | We use [`hypercorn`](https://github.com/pgjones/hypercorn/) as Conreq's production-grade webserver. This webserver can be directly exposed to the internet. For more information beyond what is in this guide, check out the [`hypercorn` documentation](https://hypercorn.readthedocs.io/en/latest/).
2 |
3 | ---
4 |
5 | The Conreq webserver can be modified through a `hypercorn.toml` file.
6 |
7 | 1. Create a `hypercorn.toml` file within your Conreq data directory (such as `./conreq/data/hypercorn.toml`)
8 |
9 | 2. Populate this `toml` file with any property in the [`hypercorn`'s documentation](https://hypercorn.readthedocs.io/en/latest/how_to_guides/configuring.html#configuration-options). For example...
10 |
11 | ```toml
12 | bind = "0.0.0.0:5357"
13 | h11_max_incomplete_size = 4
14 | keep_alive_timeout = 20
15 | use_reloader = true
16 | workers = 20
17 | ```
18 |
--------------------------------------------------------------------------------
/docs/src/contrib/apps.md:
--------------------------------------------------------------------------------
1 | Work in Progress, Conreq app framework has not been finalized.
2 |
--------------------------------------------------------------------------------
/docs/src/contrib/docs.md:
--------------------------------------------------------------------------------
1 | We use [MkDocs](https://www.mkdocs.org/#overview) to create our documentation. For more information beyond what is in this guide, check out the [MkDocs Documentation](https://www.mkdocs.org/#getting-started).
2 |
3 | ---
4 |
5 | ## Setting Up the Environment
6 |
7 | 1. Install `Python 3.x`
8 | 2. Open a terminal at the root of the repository.
9 | 3. Type `pip install -r requirements.txt` to install MkDocs.
10 |
11 | ---
12 |
13 | ## Starting the Preview Webserver
14 |
15 | MkDocs contains a tool to allow you to preview your documentation changes live! In order to use it...
16 |
17 | 1. Open a terminal at the root of the repository.
18 | 2. Type `cd docs` to enter the documentation's source code directory.
19 | 3. Type `mkdocs serve` to start the preview webserver.
20 | 4. Navigate to [`http://127.0.0.1:8000`](http://127.0.0.1:8000) to see the documentation and changes live!
21 |
22 | ---
23 |
24 | ## Adding/Editing a Docs Page
25 |
26 | 1. Create a new markdown file within `source/docs/`, or edit an existing markdown file within this folder.
27 | 2. Fill in this file with any markdown text you want!
28 | 3. _If you made a new file:_ Add this file to the navigation bar within `mkdocs.yml`.
29 | 4. Commit your changes to your GitHub branch.
30 | 5. Submit a GitHub pull request to `Archmonger/Conreq:docs`.
31 |
--------------------------------------------------------------------------------
/docs/src/develop/build_docker.md:
--------------------------------------------------------------------------------
1 | ## Software Required
2 |
3 | - Install [Docker Desktop](https://www.docker.com/products/docker-desktop/)
4 |
5 | ## Building the Docker Image
6 |
7 | 1. Pull the repository from GitHub.
8 | 2. Open a terminal at the root of the repository.
9 | 3. Type `docker build . --no-cache -t conreq` to build the Docker image.
10 |
--------------------------------------------------------------------------------
/docs/src/develop/creating_apps.md:
--------------------------------------------------------------------------------
1 | Work in Progress, Conreq app framework has not been finalized.
2 |
--------------------------------------------------------------------------------
/docs/src/develop/run_conreq.md:
--------------------------------------------------------------------------------
1 | There are two environments Conreq can exist in: [Development](#creating-a-development-environment) and [Production](#creating-a-production-environment).
2 |
3 | If you intend to edit Conreq's code, then proceed with the Development instructions.
4 |
5 | ---
6 |
7 | ## Software Required
8 |
9 | - Install [Python 3.11+](https://www.python.org/downloads/)
10 | - Make sure to select "Add Python 3.x to PATH" during installation.
11 | - Easiest if this is the only version of python on your computer
12 | - _If using Windows_: Install [Visual Studio C++](https://visualstudio.microsoft.com/visual-cpp-build-tools/) (Within this installer, navigate to _C++ Build Tools_. Select _MSVC_ and _Windows 10 SDK_)
13 | - _Optional_: Install [Visual Studio Code](https://code.visualstudio.com/) (Any editor would work)
14 |
15 | ## Creating a Development Environment
16 |
17 | 1. Pull the repository from GitHub.
18 | 2. Open a terminal as administrator at the root of the repository.
19 | 3. _If using Windows_
20 | - Type `set-executionpolicy remotesigned` and select Yes to All to allow external Python scripts to run on your computer.
21 | 4. Type `python -m venv .venv` to create a Python virtual environment called `.venv`.
22 | 5. Type `./.venv/Scripts/activate` to enter the virtual environment.
23 | 6. Type `pip install -r requirements.txt` to install all Python dependencies within the virtual environment.
24 | 7. Type `python manage.py run_conreq` to run the webserver.
25 |
26 | ---
27 |
28 | ## Creating a Production Environment
29 |
30 | Follow all instructions laid out within [Creating a Development Environment](#creating-a-development-environment), but before running `python manage.py run_conreq` do the following:
31 |
32 | 1. Set your environment variable of `DEBUG` to `false`. The method of doing this will [vary based on operating system](https://www.twilio.com/blog/2017/01/how-to-set-environment-variables.html).
33 | - Doing this enables _a lot_ of **security features**.
34 | 2. The webserver is configured with good defaults for most cases. But if you want to configure the webserver see our [webserver documentation](../configure/webserver.md) for more information.
35 | 3. Type `python manage.py run_conreq` to run the webserver.
36 |
--------------------------------------------------------------------------------
/docs/src/dictionary.txt:
--------------------------------------------------------------------------------
1 | conreq
2 | webserver
3 | unraid
4 | reddit
5 | django
6 |
--------------------------------------------------------------------------------
/docs/src/index.md:
--------------------------------------------------------------------------------
1 | [](https://hub.docker.com/r/archmonger/conreq) [](https://github.com/Archmonger/Conreq/pkgs/container/conreq) [](https://discord.gg/gQhGZzEjmX "Chat with the community and get realtime support!")
2 |
3 | ## Welcome to the Conreq Documentation
4 |
5 | Conreq is an extensible self-hosted web platform built around [Django](https://www.djangoproject.com/). Read through the docs to learn how to set up Conreq, or how to contribute to the Conreq repository!
6 |
7 | Want to join the community or have a question? Chat with us on [Discord](https://discord.gg/gQhGZzEjmX) or create a post on [GitHub Discussions](https://github.com/Archmonger/Conreq/discussions)!
8 |
9 | ---
10 |
11 | ## Communities
12 |
13 | [:fontawesome-brands-discord: Discord](https://discord.gg/gQhGZzEjmX){ .md-button .md-button--primary } [:fontawesome-brands-github: GitHub Discussions](https://github.com/Archmonger/Conreq/discussions){ .md-button .md-button--primary }
14 |
--------------------------------------------------------------------------------
/docs/src/install/docker.md:
--------------------------------------------------------------------------------
1 | These instructions configure Conreq to run within a Docker.
2 |
3 | Our dockers are published to both [DockerHub](https://hub.docker.com/r/archmonger/conreq/tags) and [GitHub Container Registry](https://github.com/Archmonger/Conreq/pkgs/container/conreq).
4 |
5 | ---
6 |
7 | ## Docker Compose
8 |
9 | 1. Create a `docker-compose.yml` file is located where you want Conreq to run.
10 |
11 | === "`docker-compose.yml`"
12 |
13 | ```yaml
14 | services:
15 | conreq:
16 | image: ghcr.io/archmonger/conreq:latest # Other tags include `develop` and version numbers (e.g. `0.21.1`)
17 | container_name: conreq
18 | environment:
19 | - PUID=99 # Optional
20 | - PGID=100 # Optional
21 | - TZ=America/Los_Angeles # If not set, defaults to UTC
22 | # Any other Conreq environment variables can also be set here
23 | volumes:
24 | - ./config:/config # You can replace ./config with the location you want to store Conreq's data.
25 | ports:
26 | - 7575:7575
27 | ```
28 |
29 | 2. Run `docker-compose up -d` to start Conreq. The `-d` flag runs the container in the background.
30 |
31 | ## Docker Run
32 |
33 | 1. Run the following command to start Conreq.
34 |
35 | ```bash
36 | docker run -d --name=conreq -e PUID=99 -e PGID=100 -e TZ=America/Los_Angeles -v ./config:/config -p 7575:7575 ghcr.io/archmonger/conreq:latest
37 | ```
38 |
39 | _Note: You can replace `./config` with the location you want to store Conreq's data._
40 |
41 | _Note 2: The `-d` flag runs the container in the background._
42 |
--------------------------------------------------------------------------------
/docs/src/install/nssm.md:
--------------------------------------------------------------------------------
1 | These instructions configure Non-Sucking Service Manager (NSSM) to automatically start Conreq as a Windows service.
2 |
3 | A traditional Windows installer is not yet available.
4 |
5 | ---
6 |
7 | ## Software Required
8 |
9 | - Install [Python 3.11+](https://www.python.org/downloads/)
10 | - Make sure to select "Add Python 3.x to PATH" during installation.
11 | - Easiest if this is the only version of python on your computer
12 | - Steps below will not work with NSSM if using the "Windows App Store" version of Python.
13 | - Install [Visual Studio C++](https://visualstudio.microsoft.com/visual-cpp-build-tools/) (Within this installer, navigate to _C++ Build Tools_. Select _MSVC_ and _Windows 10 SDK_)
14 | - Download [NSSM](https://nssm.cc/download)
15 |
16 | ## Installation
17 |
18 | 1. Create the folder `C:\Program Files\Conreq`
19 | 2. Use this folder to follow steps [setting up a Conreq environment](../develop/run_conreq.md#creating-a-production-environment), excluding steps involving `python manage.py run_conreq`.
20 | 3. Unzip NSSM in a separate directory where you can permanently keep it (such as `C:\Program Files\NSSM`).
21 | 4. Open a terminal within your NSSM directory **as administrator**.
22 | 5. Open NSSM by typing `.\win64\nssm.exe install Conreq`
23 | 6. Under the Application tab, browse to the path of your **Conreq `venv`**.
24 | - For example: `C:\Program Files\Conreq\.venv\Scripts\python.exe`
25 | 7. Under the Application tab, browse to the path of your **Conreq repository**.
26 | - For example: `C:\Program Files\Conreq\`
27 | 8. Under the Application tab, set "Arguments" to `manage.py run_conreq`
28 | 9. Click "Install Service".
29 | 10. In your terminal, type `.\win64\nssm.exe start Conreq`.
30 | - You can check to make sure its running as a service by running `nssm status Conreq`
31 | 11. Open any internet browser and navigate to [`http://127.0.0.1:7575/`](http://127.0.0.1:7575/)
32 |
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """Django's command-line utility for administrative tasks."""
3 | import os
4 | import sys
5 |
6 |
7 | def main():
8 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "conreq.settings")
9 | try:
10 | from django.core.management import execute_from_command_line
11 | except ImportError as exc:
12 | raise ImportError(
13 | "Couldn't import Django. Are you sure it's installed and "
14 | "available on your PYTHONPATH environment variable? Did you "
15 | "forget to activate a virtual environment?"
16 | ) from exc
17 | execute_from_command_line(sys.argv)
18 |
19 |
20 | if __name__ == "__main__":
21 | main()
22 |
--------------------------------------------------------------------------------
/misc/branding/circle.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/branding/circle.ai
--------------------------------------------------------------------------------
/misc/branding/circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/branding/circle.png
--------------------------------------------------------------------------------
/misc/branding/circle_outline.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/branding/circle_outline.ai
--------------------------------------------------------------------------------
/misc/branding/circle_outline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/branding/circle_outline.png
--------------------------------------------------------------------------------
/misc/branding/conreq_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/branding/conreq_logo.png
--------------------------------------------------------------------------------
/misc/branding/conreq_logo.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/branding/conreq_logo.psd
--------------------------------------------------------------------------------
/misc/branding/conreq_logo_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/branding/conreq_logo_dark.png
--------------------------------------------------------------------------------
/misc/branding/conreq_logo_dark.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/branding/conreq_logo_dark.psd
--------------------------------------------------------------------------------
/misc/branding/conreq_square.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/branding/conreq_square.ai
--------------------------------------------------------------------------------
/misc/branding/conreq_square.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/branding/conreq_square.png
--------------------------------------------------------------------------------
/misc/branding/no_bg_dark.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/branding/no_bg_dark.ai
--------------------------------------------------------------------------------
/misc/branding/no_bg_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/branding/no_bg_dark.png
--------------------------------------------------------------------------------
/misc/branding/no_bg_gradient.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/branding/no_bg_gradient.ai
--------------------------------------------------------------------------------
/misc/branding/no_bg_gradient.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/branding/no_bg_gradient.png
--------------------------------------------------------------------------------
/misc/branding/no_bg_light.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/branding/no_bg_light.ai
--------------------------------------------------------------------------------
/misc/branding/no_bg_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/branding/no_bg_light.png
--------------------------------------------------------------------------------
/misc/branding/rounded_square.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/branding/rounded_square.ai
--------------------------------------------------------------------------------
/misc/branding/rounded_square.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/branding/rounded_square.png
--------------------------------------------------------------------------------
/misc/branding/rounded_square_outline.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/branding/rounded_square_outline.ai
--------------------------------------------------------------------------------
/misc/branding/rounded_square_outline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/branding/rounded_square_outline.png
--------------------------------------------------------------------------------
/misc/legal/fontawesome_attribution.js:
--------------------------------------------------------------------------------
1 | console.log(`Font Awesome Free 5.15.1 by @fontawesome - https://fontawesome.com
2 | License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
3 | `)
--------------------------------------------------------------------------------
/misc/legal/fontawesome_license.txt:
--------------------------------------------------------------------------------
1 | Font Awesome Free License
2 | -------------------------
3 |
4 | Font Awesome Free is free, open source, and GPL friendly. You can use it for
5 | commercial projects, open source projects, or really almost whatever you want.
6 | Full Font Awesome Free license: https://fontawesome.com/license/free.
7 |
8 | # Icons: CC BY 4.0 License (https://creativecommons.org/licenses/by/4.0/)
9 | In the Font Awesome Free download, the CC BY 4.0 license applies to all icons
10 | packaged as SVG and JS file types.
11 |
12 | # Fonts: SIL OFL 1.1 License (https://scripts.sil.org/OFL)
13 | In the Font Awesome Free download, the SIL OFL license applies to all icons
14 | packaged as web and desktop font files.
15 |
16 | # Code: MIT License (https://opensource.org/licenses/MIT)
17 | In the Font Awesome Free download, the MIT license applies to all non-font and
18 | non-icon files.
19 |
20 | # Attribution
21 | Attribution is required by MIT, SIL OFL, and CC BY licenses. Downloaded Font
22 | Awesome Free files already contain embedded comments with sufficient
23 | attribution, so you shouldn't need to do anything additional when using these
24 | files normally.
25 |
26 | We've kept attribution comments terse, so we ask that you do not actively work
27 | to remove them from files, especially code. They're a great way for folks to
28 | learn about Font Awesome.
29 |
30 | # Brand Icons
31 | All brand icons are trademarks of their respective owners. The use of these
32 | trademarks does not indicate endorsement of the trademark holder by Font
33 | Awesome, nor vice versa. **Please do not use brand logos for any purpose except
34 | to represent the company, product, or service to which they refer.**
35 |
--------------------------------------------------------------------------------
/misc/other/person_placeholder.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/other/person_placeholder.psd
--------------------------------------------------------------------------------
/misc/other/poster_placeholder.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/other/poster_placeholder.psd
--------------------------------------------------------------------------------
/misc/screenshots/desktop_discover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/screenshots/desktop_discover.png
--------------------------------------------------------------------------------
/misc/screenshots/desktop_modal_episode_selection.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/screenshots/desktop_modal_episode_selection.png
--------------------------------------------------------------------------------
/misc/screenshots/desktop_modal_filter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/screenshots/desktop_modal_filter.png
--------------------------------------------------------------------------------
/misc/screenshots/desktop_modal_preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/screenshots/desktop_modal_preview.png
--------------------------------------------------------------------------------
/misc/screenshots/desktop_more_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/screenshots/desktop_more_info.png
--------------------------------------------------------------------------------
/misc/screenshots/desktop_registration.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/screenshots/desktop_registration.png
--------------------------------------------------------------------------------
/misc/screenshots/desktop_sign_in.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/screenshots/desktop_sign_in.png
--------------------------------------------------------------------------------
/misc/screenshots/mobile_discover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/screenshots/mobile_discover.png
--------------------------------------------------------------------------------
/misc/screenshots/mobile_modal_episode_selection.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/screenshots/mobile_modal_episode_selection.png
--------------------------------------------------------------------------------
/misc/screenshots/mobile_modal_filter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/screenshots/mobile_modal_filter.png
--------------------------------------------------------------------------------
/misc/screenshots/mobile_more_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/screenshots/mobile_more_info.png
--------------------------------------------------------------------------------
/misc/screenshots/mobile_registration.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/screenshots/mobile_registration.png
--------------------------------------------------------------------------------
/misc/screenshots/mobile_sidebar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/screenshots/mobile_sidebar.png
--------------------------------------------------------------------------------
/misc/screenshots/mobile_sign_in.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Archmonger/Conreq/4802485fb3fe3aa47368dcccf2022c85c3cbe3ce/misc/screenshots/mobile_sign_in.png
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | -r requirements/main.txt
2 | -r requirements/dev.txt
3 | -r requirements/docs.txt
4 |
--------------------------------------------------------------------------------
/requirements/dev.txt:
--------------------------------------------------------------------------------
1 | black
2 | pylint
3 | rope
4 | pylint_django
--------------------------------------------------------------------------------
/requirements/docs.txt:
--------------------------------------------------------------------------------
1 | mkdocs
2 | mkdocs-material
3 | mkdocs-git-revision-date-localized-plugin
4 | mkdocs-include-markdown-plugin
5 | linkcheckmd
6 | mkdocs-spellcheck[all]
7 | mkdocs-git-authors-plugin
8 | mkdocs-minify-plugin
9 | mike
10 |
--------------------------------------------------------------------------------
/requirements/main.txt:
--------------------------------------------------------------------------------
1 | channels[daphne]==4.0.0
2 | diskcache==5.6.3
3 | django==3.2.25
4 | django-cleanup==8.1.0
5 | django-compression-middleware==0.5.0
6 | django-compressor==4.4
7 | django-htmlmin==0.11.0
8 | django-model-utils==4.5.1
9 | django-searchable-encrypted-fields==0.2.1
10 | django-silk==5.1.0
11 | django-solo==2.2.0
12 | django-url-or-relative-url-field==0.2.0
13 | djangorestframework==3.15.1
14 | djangorestframework-api-key==3.0.0
15 | docutils==0.21.2
16 | drf-yasg==1.21.7
17 | huey==2.5.1
18 | hypercorn[h3]==0.17.3
19 | jsonfield==3.1.0
20 | markdown==3.6.0
21 | pwned-passwords-django==2.1
22 | pyarr==5.2.0
23 | pymysql==1.1.1
24 | python-dotenv==1.0.1
25 | strsim==0.0.3
26 | titlecase==2.4.1
27 | tmdbsimple==2.9.1
28 | Twisted[tls,http2]==24.3.0
29 | tzlocal==5.2
30 | whitenoise[brotli]==6.7.0
31 | attrs
32 |
--------------------------------------------------------------------------------