Skip to content

Commit 3465dac

Browse files
author
Mikhail Pyrev
committed
Initial
0 parents  commit 3465dac

File tree

27 files changed

+544
-0
lines changed

27 files changed

+544
-0
lines changed

.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
*.sqlite3
2+
__pycache__/
3+
*.pyc
4+
.idea/
5+
dist/
6+
*.egg-info/

LICENSE

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Copyright (c) 2017 Mikhail Pyrev <[email protected]>
2+
3+
Permission is hereby granted, free of charge, to any person obtaining
4+
a copy of this software and associated documentation files (the
5+
"Software"), to deal in the Software without restriction, including
6+
without limitation the rights to use, copy, modify, merge, publish,
7+
distribute, sublicense, and/or sell copies of the Software, and to
8+
permit persons to whom the Software is furnished to do so, subject to
9+
the following conditions:
10+
11+
The above copyright notice and this permission notice shall be
12+
included in all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

MANIFEST.in

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
include LICENSE
2+
include README.md
3+
recursive-include host_user_override/locale *
4+
recursive-include host_user_override/static *
5+
recursive-include host_user_override/templates *

README.md

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# django-host-user-override
2+
3+
Overrides current user based on host prefix. For example any request to
4+
```5.user.example.com``` becomes request as if you were logged in as
5+
user with ID 5. Works only if you're actually logged in as superuser.
6+
7+
Also gives you big red banner on top of every page if your user is
8+
overridden.
9+
10+
### Installing django-host-user-override
11+
12+
1. Install the package from PyPI: ```pip install django-host-user-override```
13+
14+
2. Add ```host_user_override``` to ```INSTALLED_APPS```:
15+
```python
16+
INSTALLED_APPS = [
17+
...,
18+
'host_user_override',
19+
...,
20+
]
21+
```
22+
23+
3. Add ```HostUserOverrideMiddleware``` right after ```AuthenticationMiddleware```:
24+
```python
25+
MIDDLEWARE = [
26+
...,
27+
'django.contrib.auth.middleware.AuthenticationMiddleware',
28+
'host_user_override.middleware.HostUserOverrideMiddleware',
29+
...,
30+
]
31+
```
32+
33+
4. Update your ```settings.py``` file to support subdomains (don't forget about DNS as well):
34+
```python
35+
ALLOWED_HOSTS = ['.example.com']
36+
37+
SESSION_COOKIE_DOMAIN = '.example.com'
38+
```
39+
40+
5. Set new ```change_form.html``` template in ```UserAdmin```:
41+
```python
42+
admin.site.unregister(User)
43+
44+
@admin.register(User)
45+
class CustomUserAdmin(UserAdmin):
46+
change_form_template = 'host_user_override/change_form.html'
47+
```
48+
49+
## Usage
50+
51+
Open any non-superuser in Django Admin and press 'Login as multiuser' button.
52+
53+
## License
54+
55+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
56+
57+
## Acknowledgments
58+
59+
* Props to django-debug-toolbar team for HTML injection code
60+
* Thanks to @dimoha for original idea

example/app/__init__.py

Whitespace-only changes.

example/app/admin.py

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# coding: utf-8
2+
from __future__ import unicode_literals
3+
4+
from django.contrib import admin
5+
from django.contrib.auth import get_user_model
6+
from django.contrib.auth.admin import UserAdmin
7+
8+
User = get_user_model()
9+
10+
admin.site.unregister(User)
11+
12+
13+
@admin.register(User)
14+
class CustomUserAdmin(UserAdmin):
15+
change_form_template = 'host_user_override/change_form.html'

example/app/apps.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from django.apps import AppConfig
2+
3+
4+
class AppConfig(AppConfig):
5+
name = 'app'

example/app/templates/app/index.html

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Title</title>
6+
</head>
7+
<body>{{ request.user.pk }}:{{ request.user }}</body>
8+
</html>

example/app/tests.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from django.test import TestCase
2+
3+
# Create your tests here.

example/app/views.py

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# coding: utf-8
2+
from __future__ import unicode_literals
3+
4+
from django.views.generic import TemplateView
5+
6+
7+
class IndexView(TemplateView):
8+
template_name = 'app/index.html'

example/example/__init__.py

Whitespace-only changes.

example/example/settings.py

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
"""
2+
Django settings for example project.
3+
4+
Generated by 'django-admin startproject' using Django 1.11.8.
5+
6+
For more information on this file, see
7+
https://docs.djangoproject.com/en/1.11/topics/settings/
8+
9+
For the full list of settings and their values, see
10+
https://docs.djangoproject.com/en/1.11/ref/settings/
11+
"""
12+
13+
import os
14+
15+
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
16+
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
17+
18+
19+
# Quick-start development settings - unsuitable for production
20+
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
21+
22+
# SECURITY WARNING: keep the secret key used in production secret!
23+
SECRET_KEY = 'yw3iypngd#!7qy27z!)$5sfdg$+%k10y(x6ecj!q&7b+%be)x!'
24+
25+
# SECURITY WARNING: don't run with debug turned on in production!
26+
DEBUG = True
27+
28+
ALLOWED_HOSTS = ['.host-user-override.dev']
29+
30+
SESSION_COOKIE_DOMAIN = '.host-user-override.dev'
31+
32+
33+
# Application definition
34+
35+
INSTALLED_APPS = [
36+
'django.contrib.admin',
37+
'django.contrib.auth',
38+
'django.contrib.contenttypes',
39+
'django.contrib.sessions',
40+
'django.contrib.messages',
41+
'django.contrib.staticfiles',
42+
'host_user_override',
43+
'app',
44+
]
45+
46+
MIDDLEWARE = [
47+
'django.middleware.security.SecurityMiddleware',
48+
'django.contrib.sessions.middleware.SessionMiddleware',
49+
'django.middleware.common.CommonMiddleware',
50+
'django.middleware.csrf.CsrfViewMiddleware',
51+
'django.contrib.auth.middleware.AuthenticationMiddleware',
52+
'host_user_override.middleware.HostUserOverrideMiddleware',
53+
'django.contrib.messages.middleware.MessageMiddleware',
54+
'django.middleware.clickjacking.XFrameOptionsMiddleware',
55+
]
56+
57+
ROOT_URLCONF = 'example.urls'
58+
59+
TEMPLATES = [
60+
{
61+
'BACKEND': 'django.template.backends.django.DjangoTemplates',
62+
'DIRS': [],
63+
'APP_DIRS': True,
64+
'OPTIONS': {
65+
'context_processors': [
66+
'django.template.context_processors.debug',
67+
'django.template.context_processors.request',
68+
'django.contrib.auth.context_processors.auth',
69+
'django.contrib.messages.context_processors.messages',
70+
],
71+
},
72+
},
73+
]
74+
75+
WSGI_APPLICATION = 'example.wsgi.application'
76+
77+
78+
# Database
79+
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
80+
81+
DATABASES = {
82+
'default': {
83+
'ENGINE': 'django.db.backends.sqlite3',
84+
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
85+
}
86+
}
87+
88+
89+
# Password validation
90+
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
91+
92+
AUTH_PASSWORD_VALIDATORS = [
93+
{
94+
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
95+
},
96+
{
97+
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
98+
},
99+
{
100+
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
101+
},
102+
{
103+
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
104+
},
105+
]
106+
107+
108+
# Internationalization
109+
# https://docs.djangoproject.com/en/1.11/topics/i18n/
110+
111+
LANGUAGE_CODE = 'en'
112+
113+
TIME_ZONE = 'UTC'
114+
115+
USE_I18N = True
116+
117+
USE_L10N = True
118+
119+
USE_TZ = True
120+
121+
122+
# Static files (CSS, JavaScript, Images)
123+
# https://docs.djangoproject.com/en/1.11/howto/static-files/
124+
125+
STATIC_URL = '/static/'

example/example/urls.py

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"""example URL Configuration
2+
3+
The `urlpatterns` list routes URLs to views. For more information please see:
4+
https://docs.djangoproject.com/en/1.11/topics/http/urls/
5+
Examples:
6+
Function views
7+
1. Add an import: from my_app import views
8+
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
9+
Class-based views
10+
1. Add an import: from other_app.views import Home
11+
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
12+
Including another URLconf
13+
1. Import the include() function: from django.conf.urls import url, include
14+
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
15+
"""
16+
from django.conf.urls import url
17+
from django.contrib import admin
18+
19+
from app import views
20+
21+
22+
urlpatterns = [
23+
url(r'^admin/', admin.site.urls),
24+
url(r'^$', views.IndexView.as_view()),
25+
]

example/example/wsgi.py

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""
2+
WSGI config for example project.
3+
4+
It exposes the WSGI callable as a module-level variable named ``application``.
5+
6+
For more information on this file, see
7+
https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/
8+
"""
9+
10+
import os
11+
12+
from django.core.wsgi import get_wsgi_application
13+
14+
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example.settings")
15+
16+
application = get_wsgi_application()

example/manage.py

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/usr/bin/env python
2+
import os
3+
import sys
4+
5+
# Add our app to PYTHONPATH
6+
sys.path.append(os.path.join(os.path.dirname(__file__), '../'))
7+
8+
if __name__ == "__main__":
9+
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example.settings")
10+
try:
11+
from django.core.management import execute_from_command_line
12+
except ImportError:
13+
# The above import may fail for some other reason. Ensure that the
14+
# issue is really that Django is missing to avoid masking other
15+
# exceptions on Python 2.
16+
try:
17+
import django
18+
except ImportError:
19+
raise ImportError(
20+
"Couldn't import Django. Are you sure it's installed and "
21+
"available on your PYTHONPATH environment variable? Did you "
22+
"forget to activate a virtual environment?"
23+
)
24+
raise
25+
execute_from_command_line(sys.argv)

host_user_override/__init__.py

Whitespace-only changes.

host_user_override/apps.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from django.apps import AppConfig
2+
3+
4+
class HostUserOverrideConfig(AppConfig):
5+
name = 'host_user_override'
943 Bytes
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# SOME DESCRIPTIVE TITLE.
2+
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3+
# This file is distributed under the same license as the PACKAGE package.
4+
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5+
#
6+
#, fuzzy
7+
msgid ""
8+
msgstr ""
9+
"Project-Id-Version: PACKAGE VERSION\n"
10+
"Report-Msgid-Bugs-To: \n"
11+
"POT-Creation-Date: 2017-12-15 14:59+0300\n"
12+
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13+
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14+
"Language-Team: LANGUAGE <[email protected]>\n"
15+
"Language: \n"
16+
"MIME-Version: 1.0\n"
17+
"Content-Type: text/plain; charset=UTF-8\n"
18+
"Content-Transfer-Encoding: 8bit\n"
19+
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
20+
"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n"
21+
"%100>=11 && n%100<=14)? 2 : 3);\n"
22+
23+
#: templates/host_user_override/banner.html:11
24+
#, python-format
25+
msgid "You're logged in as %(user)s."
26+
msgstr "Вы вошли как %(user)s."
27+
28+
#: templates/host_user_override/banner.html:14
29+
#, python-format
30+
msgid ""
31+
"Get back to admin as <a href=\"//%(original_host)s%(admin_index)s\">"
32+
"%(original)s</a>."
33+
msgstr ""
34+
"Вернуться в админку как <a href=\"//%(original_host)s%(admin_index)s\">"
35+
"%(original)s</a>."
36+
37+
#: templates/host_user_override/change_form.html:7
38+
msgid "Login as multiuser"
39+
msgstr "Зайти как мультипользователь"

0 commit comments

Comments
 (0)