├── chat ├── __init__.py ├── routing.py ├── apps.py ├── urls.py ├── serializers.py ├── templates │ └── chat │ │ ├── about.html │ │ ├── create-group.html │ │ ├── index.html │ │ ├── group-list.html │ │ └── room.html ├── admin.py ├── views.py ├── test_consumer.py ├── consumer.py ├── tests_models.py └── models.py ├── core ├── __init__.py ├── urls.py ├── wsgi.py ├── asgi.py └── settings.py ├── auth ├── __init__.py ├── apps.py ├── urls.py ├── views.py └── templates │ └── auth │ ├── register.html │ └── login.html ├── .gitignore ├── static ├── assets │ ├── favicon.ico │ └── IRANSansWeb.woff2 ├── css │ ├── about.css │ ├── style.css │ ├── chat.css │ └── auth.css ├── js │ └── reconnecting_ws.js └── base.css ├── .gitattributes ├── templates ├── adminlte │ ├── index.html │ ├── lib │ │ ├── _main_footer.html │ │ ├── _styles.html │ │ ├── _scripts.html │ │ ├── _messages.html │ │ ├── _pagination.html │ │ ├── _main_sidebar.html │ │ └── _main_header.html │ ├── components │ │ └── info_box.html │ ├── example.html │ ├── pages │ │ ├── index.html │ │ └── edit.html │ ├── login.html │ └── base.html ├── admin │ ├── lib │ │ ├── _main_sidebar.html │ │ └── _main_header.html │ ├── base_site.html │ ├── app_index.html │ ├── search_form.html │ ├── base.html │ ├── change_list_results.html │ ├── includes │ │ └── fieldset.html │ ├── base_login.html │ ├── login.html │ ├── object_history.html │ ├── change_form.html │ ├── change_list.html │ └── index.html └── base.html ├── .env ├── requirements.txt ├── manage.py ├── LICENSE └── README.md /chat/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /core/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /auth/__init__.py: -------------------------------------------------------------------------------- 1 | from email.policy import default 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | env/ 2 | __pycache__ 3 | migrations/ 4 | test/ 5 | staticfiles/ -------------------------------------------------------------------------------- /static/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dori-dev/django-chat/HEAD/static/assets/favicon.ico -------------------------------------------------------------------------------- /static/assets/IRANSansWeb.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dori-dev/django-chat/HEAD/static/assets/IRANSansWeb.woff2 -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.css linguist-detectable=false 2 | *.js linguist-detectable=false 3 | *.html linguist-detectable=false 4 | -------------------------------------------------------------------------------- /templates/adminlte/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'adminlte/base.html' %} 2 | 3 | {% block content %} 4 | your awesome content 5 | {% endblock %} 6 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | SECRET_KEY=abc 2 | DEBUG=1 3 | ALLOWED_HOSTS=127.0.0.1,localhost 4 | DB_NAME=chat_data 5 | DB_USER=postgres 6 | DB_PASSWORD=password 7 | DB_HOST=localhost 8 | DB_POST=5432 -------------------------------------------------------------------------------- /auth/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AuthConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'auth.apps' 7 | label = 'authentication' 8 | -------------------------------------------------------------------------------- /chat/routing.py: -------------------------------------------------------------------------------- 1 | """chat routing 2 | """ 3 | from django.urls import re_path 4 | from . import consumer 5 | 6 | websocket_urlpatterns = [ 7 | re_path(r'ws/id/(?P\w+)/$', consumer.ChatConsumer.as_asgi()), 8 | ] 9 | -------------------------------------------------------------------------------- /templates/admin/lib/_main_sidebar.html: -------------------------------------------------------------------------------- 1 | {% extends 'adminlte/lib/_main_sidebar.html' %} 2 | {% load admin_menu %} 3 | 4 | {% block nav_links %} 5 | {% autoescape off %}{% menu %}{% endautoescape %} 6 | {% endblock nav_links %} 7 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | channels==3.0.4 2 | Django==4.0.3 3 | channels-redis==3.4.0 4 | selenium==4.1.3 5 | djangorestframework==3.13.1 6 | Markdown==3.3.6 7 | django-filter==21.1 8 | psycopg2==2.9.3 9 | django-adminlte-3==0.1.6 10 | django-dotenv==1.4.2 11 | django-colorfield==0.6.3 12 | -------------------------------------------------------------------------------- /core/urls.py: -------------------------------------------------------------------------------- 1 | """core URL Configuration 2 | """ 3 | from django.contrib import admin 4 | from django.urls import path, include 5 | 6 | urlpatterns = [ 7 | path('admin/', admin.site.urls), 8 | path('', include('chat.urls')), 9 | path('auth/', include('auth.urls')), 10 | ] 11 | -------------------------------------------------------------------------------- /auth/urls.py: -------------------------------------------------------------------------------- 1 | """auth urls 2 | """ 3 | from django.urls import path 4 | from . import views 5 | 6 | app_name = "auth" 7 | urlpatterns = [ 8 | path("register/", views.register_view, name="register"), 9 | path("login/", views.login_view, name="login"), 10 | path("logout/", views.logout_view, name="logout"), 11 | ] 12 | -------------------------------------------------------------------------------- /templates/admin/base_site.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base.html" %} 2 | 3 | {% block title %}نیوچت - دری ادمین{% endblock %} 4 | 5 | {% block branding %} 6 |

{{ site_header|default:_('Django administration') }}

7 | {% endblock %} 8 | 9 | {% block nav-global %}{% endblock %} 10 | -------------------------------------------------------------------------------- /chat/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ChatConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'chat' 7 | verbose_name = "گفتگو" 8 | 9 | def ready(self): 10 | try: 11 | from .models import Customize 12 | if len(Customize.objects.all()) == 0: 13 | Customize.create_default_fields() 14 | except Exception: 15 | pass 16 | -------------------------------------------------------------------------------- /core/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for core 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/3.2/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', 'core.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /static/css/about.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-size: 19px; 3 | } 4 | 5 | h1 { 6 | margin: 30px 10px 40px 0; 7 | } 8 | 9 | a { 10 | color: #007bff; 11 | text-decoration: none; 12 | background-color: transparent; 13 | -webkit-text-decoration-skip: objects; 14 | text-decoration: none; 15 | } 16 | 17 | a:visited, 18 | a:hover { 19 | color: #0056b3; 20 | text-decoration: underline; 21 | } 22 | 23 | .about p { 24 | margin: 7px 25px 0 0; 25 | } 26 | .social p { 27 | margin: 10px 25px 0 0; 28 | } 29 | -------------------------------------------------------------------------------- /chat/urls.py: -------------------------------------------------------------------------------- 1 | """chat urls 2 | """ 3 | from django.urls import path 4 | from . import views 5 | 6 | urlpatterns = [ 7 | path('', views.index, name='index'), 8 | path('chat/', views.index, name='index'), 9 | path('groups/', views.group_list, name="groups"), 10 | path('create/', views.create_group, name='create'), 11 | path('about/', views.about, name='about'), 12 | path('chat//', views.room, name='room'), 13 | path('id//', views.group_view, name='room'), 14 | ] 15 | -------------------------------------------------------------------------------- /templates/adminlte/lib/_main_footer.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | {% block footer_right %} 4 | ورژن {% block version %}1.1{% endblock %} دری ادمین 5 | {% endblock %} 6 |
7 | 8 | {% block footer_left %} 9 | {% block legal %} 10 | نیوچت © 11 | {% now "Y" %} - 12 | محمد دری 13 | {% endblock %} 14 | {% endblock %} 15 |
-------------------------------------------------------------------------------- /chat/serializers.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from rest_framework import serializers 3 | from .models import Message 4 | 5 | 6 | class MessageSerializer(serializers.ModelSerializer): 7 | time = serializers.SerializerMethodField() 8 | 9 | class Meta: 10 | model = Message 11 | fields = ['author_username', 'content', 'type', 'time'] 12 | 13 | def get_time(self, message: Message): 14 | time = datetime.strftime( 15 | message.timestamp.astimezone(), 16 | "%I:%M %p") 17 | return time 18 | -------------------------------------------------------------------------------- /core/asgi.py: -------------------------------------------------------------------------------- 1 | """ASGI config for core project. 2 | """ 3 | 4 | import os 5 | from channels.auth import AuthMiddlewareStack 6 | from channels.routing import ProtocolTypeRouter, URLRouter 7 | from django.core.asgi import get_asgi_application 8 | import chat.routing 9 | 10 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings') 11 | 12 | application = ProtocolTypeRouter({ 13 | "http": get_asgi_application(), 14 | "websocket": AuthMiddlewareStack( 15 | URLRouter( 16 | chat.routing.websocket_urlpatterns 17 | ) 18 | ), 19 | }) 20 | -------------------------------------------------------------------------------- /static/css/style.css: -------------------------------------------------------------------------------- 1 | ul li { 2 | display: block; 3 | } 4 | 5 | ul a { 6 | text-decoration: none; 7 | } 8 | 9 | .search { 10 | margin-top: 20px; 11 | margin-right: 10px; 12 | } 13 | 14 | .title { 15 | margin-top: 60px; 16 | margin-right: 10px; 17 | } 18 | 19 | .hint { 20 | margin-top: 30px; 21 | } 22 | 23 | .submit-btn { 24 | font-size: larger; 25 | margin-top: -10px; 26 | } 27 | 28 | .group-input { 29 | max-width: 600px; 30 | font-size: large; 31 | } 32 | 33 | .custom-btn { 34 | margin: 10px; 35 | } 36 | 37 | .all-group-btn { 38 | font-size: large; 39 | margin: 10px; 40 | } -------------------------------------------------------------------------------- /templates/adminlte/lib/_styles.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | {% block styles %} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /templates/adminlte/lib/_scripts.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | {% block scripts %} 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | {% block datatable_js %}{% endblock %} 14 | 15 | 16 | 17 | {% endblock %} 18 | -------------------------------------------------------------------------------- /templates/admin/app_index.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/index.html" %} 2 | {% load i18n %} 3 | 4 | {% block bodyclass %}{{ block.super }} app-{{ app_label }}{% endblock %} 5 | 6 | {% if not is_popup %} 7 | {% block breadcrumbs %} 8 |
9 |
10 |

{{app_label}}

11 |
12 |
13 | 19 |
20 |
21 | {% endblock %} 22 | {% endif %} 23 | 24 | 25 | -------------------------------------------------------------------------------- /templates/adminlte/components/info_box.html: -------------------------------------------------------------------------------- 1 | {% load humanize %} 2 |
3 | {% if not hide_icon %} 4 | 5 | {% endif %} 6 |
7 | {{ header }} 8 | {{ number }} {{ unit }} 9 | {% if percent %} 10 |
11 |
12 |
13 | {% if how_long %} 14 | 15 | {{ percent }}% Increase in {{ how_long }} 16 | 17 | {% endif %} 18 | {% endif %} 19 |
20 |
21 | -------------------------------------------------------------------------------- /templates/adminlte/lib/_messages.html: -------------------------------------------------------------------------------- 1 | {% if messages %} 2 | {% for message in messages %} 3 | {% if message.level == DEFAULT_MESSAGE_LEVELS.SUCCESS %} 4 |
5 | 6 | {{ message }} 7 |
8 | {% elif message.level == DEFAULT_MESSAGE_LEVELS.ERROR %} 9 |
10 | 11 | {{ message }} 12 |
13 | {% else %} 14 |
15 | 16 | {{ message }} 17 |
18 | {% endif %} 19 | {% endfor %} 20 | {% endif %} 21 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | import dotenv 6 | import pathlib 7 | 8 | 9 | def main(): 10 | """Run administrative tasks.""" 11 | DOT_ENV_PATH = pathlib.Path() / '.env' 12 | if DOT_ENV_PATH.exists(): 13 | dotenv.read_dotenv(DOT_ENV_PATH) 14 | else: 15 | print("No .env found, be sure to make it!") 16 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings') 17 | try: 18 | from django.core.management import execute_from_command_line 19 | except ImportError as exc: 20 | raise ImportError( 21 | "Couldn't import Django. Are you sure it's installed and " 22 | "available on your PYTHONPATH environment variable? Did you " 23 | "forget to activate a virtual environment?" 24 | ) from exc 25 | execute_from_command_line(sys.argv) 26 | 27 | 28 | if __name__ == '__main__': 29 | main() 30 | -------------------------------------------------------------------------------- /templates/adminlte/example.html: -------------------------------------------------------------------------------- 1 | {% extends 'adminlte/base.html' %} 2 | 3 | {% block content %} 4 | 5 |
6 |
7 |

Title

8 | 9 |
10 | 13 | 16 |
17 |
18 |
19 | Start creating your amazing application! 20 |
21 | 22 | 25 | 26 |
27 | 28 | {% endblock %} 29 | -------------------------------------------------------------------------------- /chat/templates/chat/about.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% load static %} 3 | 4 | 5 | {% block style %} 6 | 7 | {% endblock style %} 8 | 9 | 10 | {% block title %} 11 | درباره من 12 | {% endblock title %} 13 | 14 | 15 | {% block content %} 16 |

درباره من

17 |
18 |

سلام، من محمد دری ام سازنده نیوچت

19 |

به نیوچت خوش اومدی :)

20 |

امیدوارم که از نیوچت لذت ببری!

21 |

آشنایی بیشتر با پیامرسان نیوچت

22 |
23 |
24 | 31 | {% endblock content %} -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Mohammad Dori 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 | -------------------------------------------------------------------------------- /chat/templates/chat/create-group.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% load static %} 3 | 4 | {% block style %} 5 | 6 | {% endblock style %} 7 | 8 | 9 | {% block title %} 10 | نیوچت - ساخت گروه 11 | {% endblock title %} 12 | {% block content %} 13 | 14 | 20 | 37 | {% endblock content %} -------------------------------------------------------------------------------- /templates/adminlte/pages/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'adminlte/base.html' %} 2 | 3 | {% block content %} 4 |
5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {% for page in pager.items %} 15 | 16 | 17 | 18 | 19 | 20 | {% endfor %} 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
#TitleUrl
{{ forloop.counter }}{{ page.title }}编辑
#TitleUrl
29 |
30 | 31 | 34 |
35 | {% endblock %} 36 | -------------------------------------------------------------------------------- /templates/admin/search_form.html: -------------------------------------------------------------------------------- 1 | {% load i18n static %} 2 | 3 | {% if cl.search_fields %} 4 | 5 | 26 | 27 | {% endif %} -------------------------------------------------------------------------------- /templates/admin/base.html: -------------------------------------------------------------------------------- 1 | {% extends 'adminlte/base.html' %} 2 | {% load static i18n %} 3 | 4 | {% block extra_head %} 5 | {{ block.super }} 6 | 7 | {% if LANGUAGE_BIDI %} 8 | 10 | {% endif %} 11 | 13 | {% block extrastyle %}{% endblock %} 14 | {% block extrahead %}{% endblock %} 15 | {% block blockbots %} 16 | {% endblock %} 17 | {% endblock %} 18 | 19 | {% block nav_header %} 20 | {% include 'admin/lib/_main_header.html' %} 21 | {% endblock %} 22 | 23 | {% block nav_sidebar %} 24 | {% include 'admin/lib/_main_sidebar.html' %} 25 | {% endblock %} 26 | 27 | {% block content_header %} 28 |
29 |
30 | {% block breadcrumbs %} 31 | 35 | {% endblock %} 36 |
37 |
38 | 39 | {% endblock %} 40 | 41 | {% block content_block_wrap %} 42 | 43 | {% block content %} 44 | {% block object-tools %}{% endblock %} 45 | {{ content }} 46 | {% block sidebar %}{% endblock %} 47 | {% endblock %} 48 | 49 | 50 | {% endblock %} -------------------------------------------------------------------------------- /templates/admin/change_list_results.html: -------------------------------------------------------------------------------- 1 | {% load i18n admin_urls adminlte_helpers static admin_list %} 2 | {% block extrahead %} 3 | 4 | {% endblock %} 5 | 6 | {% if result_hidden_fields %} 7 |
{# DIV for HTML validation #} 8 | {% for item in result_hidden_fields %}{{ item }}{% endfor %} 9 |
10 | {% endif %} 11 | {% if results %} 12 |
13 |
14 |
15 |
16 | 17 | 18 | 19 | {% for header in result_headers %} 20 | {% endfor %} 23 | 24 | 25 | 26 | {% for result in results %} 27 | {% if result.form.non_field_errors %} 28 | 29 | 30 | 31 | {% endif %} 32 | {% for item in result %}{{ item }}{% endfor %} 33 | {% endfor %} 34 | 35 |
21 | {{ header.text|capfirst }} 22 |
{{ result.form.non_field_errors }}
36 |
37 |
38 |
39 |
40 | 41 | {% endif %} 42 | 43 | -------------------------------------------------------------------------------- /auth/views.py: -------------------------------------------------------------------------------- 1 | """chat authentication 2 | """ 3 | from django.shortcuts import render, redirect 4 | from django.contrib.auth.forms import UserCreationForm, AuthenticationForm 5 | from django.contrib.auth import login, logout 6 | 7 | 8 | def register_view(request): 9 | """register view""" 10 | if request.method == "POST": 11 | form = UserCreationForm(request.POST) 12 | if form.is_valid(): 13 | user = form.save() 14 | login(request, user) 15 | if "next" in request.POST: 16 | return redirect(request.POST.get('next')) 17 | return redirect("index") 18 | 19 | else: 20 | form = UserCreationForm() 21 | arg = { 22 | "form": form, 23 | } 24 | return render(request, "auth/register.html", arg) 25 | 26 | 27 | def login_view(request): 28 | """login view""" 29 | if request.method == "POST": 30 | form = AuthenticationForm(data=request.POST) 31 | if form.is_valid(): 32 | user = form.get_user() 33 | login(request, user) 34 | if "next" in request.POST: 35 | return redirect(request.POST.get('next')) 36 | return redirect("index") 37 | else: 38 | form = AuthenticationForm() 39 | arg = { 40 | "form": form, 41 | } 42 | return render(request, "auth/login.html", arg) 43 | 44 | 45 | def logout_view(request): 46 | """logout view""" 47 | if request.method == "POST": 48 | logout(request) 49 | return redirect("index") 50 | -------------------------------------------------------------------------------- /templates/adminlte/lib/_pagination.html: -------------------------------------------------------------------------------- 1 | {% if pager and ROOT_MENU.current_menu.view_name %} 2 | 39 | {% endif %} 40 | -------------------------------------------------------------------------------- /templates/adminlte/pages/edit.html: -------------------------------------------------------------------------------- 1 | {% extends 'adminlte/base.html' %} 2 | 3 | {% block header_tail %} 4 | 5 | 6 | 7 | {% endblock %} 8 | 9 | {% block content %} 10 |
11 | 12 |
{% csrf_token %} 13 |
14 |
15 | 16 | 17 |
18 |
19 | 20 | 21 |
22 |
23 | 24 | 25 | 28 |
29 |
30 | 31 | {% endblock %} 32 | 33 | {% block body_tail %} 34 | 47 | {% endblock %} 48 | -------------------------------------------------------------------------------- /templates/admin/includes/fieldset.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

{% if fieldset.name %}{{ fieldset.name }}{% endif %}

4 | {% if fieldset.description %} 5 |
{{ fieldset.description|safe }}
6 | {% endif %} 7 |
8 | 10 |
11 |
12 |
13 | {% for line in fieldset %} 14 |
16 | {% if line.fields|length_is:'1' %}{{ line.errors }}{% endif %} 17 | {% for field in line %} 18 | 19 |
20 | {% if field.is_checkbox %} 21 | {{ field.field }} 22 | {% else %} 23 | 24 | {% if field.is_readonly %} 25 |
{{ field.contents }}
26 | {% else %} 27 | {{ field.field }} 28 | {% endif %} 29 | {% endif %} 30 | {% if field.field.help_text %} 31 |
{{ field.field.help_text|safe }}
32 | {% endif %} 33 |
34 | 35 | 36 | {% endfor %} 37 |
38 | {% endfor %} 39 |
40 |
-------------------------------------------------------------------------------- /templates/admin/base_login.html: -------------------------------------------------------------------------------- 1 | {% load i18n static %} 2 | {% get_current_language as LANGUAGE_CODE %}{% get_current_language_bidi as LANGUAGE_BIDI %} 3 | 4 | 5 | 6 | 7 | {% block title %}{% endblock %} 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 20 | 21 |