add very basic login/logout forms, stream management forms
This commit is contained in:
		
							parent
							
								
									96f6ebebe1
								
							
						
					
					
						commit
						76aac4d59f
					
				| 
						 | 
				
			
			@ -9,16 +9,20 @@ services:
 | 
			
		|||
      - postgres
 | 
			
		||||
      - redis
 | 
			
		||||
    environment:
 | 
			
		||||
      DEBUG: 1
 | 
			
		||||
      SECRET_KEY: "D4mn1t_Ch4nG3_M3!1!!"
 | 
			
		||||
      SQL_ENGINE: django.db.backends.postgresql
 | 
			
		||||
      SQL_USER: portier
 | 
			
		||||
      SQL_PASSWORD: portier
 | 
			
		||||
      SQL_DATABASE: portier
 | 
			
		||||
      SQL_HOST: postgres
 | 
			
		||||
      SQL_PORT: 5432
 | 
			
		||||
      REDIS_HOST: redis
 | 
			
		||||
      REDIS_PORT: 6379
 | 
			
		||||
      - DEBUG=1
 | 
			
		||||
      - "SECRET_KEY=D4mn1t_Ch4nG3_M3!1!!"
 | 
			
		||||
      - SQL_ENGINE=django.db.backends.postgresql
 | 
			
		||||
      - SQL_USER=portier
 | 
			
		||||
      - SQL_PASSWORD=portier
 | 
			
		||||
      - SQL_DATABASE=portier
 | 
			
		||||
      - SQL_HOST=postgres
 | 
			
		||||
      - SQL_PORT=5432
 | 
			
		||||
      - REDIS_HOST=redis
 | 
			
		||||
      - REDIS_PORT=6379
 | 
			
		||||
      - "EMAIL_FROM=${EMAIL_FROM}"
 | 
			
		||||
      - "EMAIL_HOST=${EMAIL_HOST}"
 | 
			
		||||
      - "EMAIL_HOST_USER=${EMAIL_HOST_USER}"
 | 
			
		||||
      - "EMAIL_HOST_PASSWORD=${EMAIL_HOST_PASSWORD}"
 | 
			
		||||
  redis:
 | 
			
		||||
    image: redis:5-alpine
 | 
			
		||||
  postgres:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,11 @@
 | 
			
		|||
{% extends 'base.html' %}
 | 
			
		||||
 | 
			
		||||
{% block 'body' %}
 | 
			
		||||
<main class="container" role="main">
 | 
			
		||||
  <h1>Portier</h1>
 | 
			
		||||
  <p class="leader">Nothing to see here yet. We're working on it, though!</p>
 | 
			
		||||
  <p><a href="https://github.com/chaoswest-tv/portier">See progress on GitHub</a></p>
 | 
			
		||||
</main>
 | 
			
		||||
{% block 'content' %}
 | 
			
		||||
  <div class="jumbotron">
 | 
			
		||||
    <h1 class="display-4">Hello, world!</h1>
 | 
			
		||||
    <p class="leader">Nothing to see here yet. We're working on it, though!</p>
 | 
			
		||||
    <hr class="my-4">
 | 
			
		||||
    <p>Portier will be a pretty cool streaming platform, built by and for nerds. You are welcome to contribute, be it code, ideas, documentation, design or something else entirely.</p>
 | 
			
		||||
    <a class="btn btn-primary btn-lg" href="https://github.com/chaoswest-tv/portier" role="button">Code on GitHub</a>
 | 
			
		||||
  </div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,6 +36,7 @@ INSTALLED_APPS = [
 | 
			
		|||
    'django.contrib.sessions',
 | 
			
		||||
    'django.contrib.messages',
 | 
			
		||||
    'django.contrib.staticfiles',
 | 
			
		||||
    'django_registration',
 | 
			
		||||
    'bootstrap4',
 | 
			
		||||
    'fa',
 | 
			
		||||
    'portal.apps.PortalConfig',
 | 
			
		||||
| 
						 | 
				
			
			@ -108,26 +109,37 @@ AUTH_PASSWORD_VALIDATORS = [
 | 
			
		|||
    },
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
# Django-Registration
 | 
			
		||||
 | 
			
		||||
ACCOUNT_ACTIVATION_DAYS = 7
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Internationalization
 | 
			
		||||
# https://docs.djangoproject.com/en/3.0/topics/i18n/
 | 
			
		||||
 | 
			
		||||
LANGUAGE_CODE = 'en-us'
 | 
			
		||||
 | 
			
		||||
TIME_ZONE = 'UTC'
 | 
			
		||||
 | 
			
		||||
USE_I18N = True
 | 
			
		||||
 | 
			
		||||
USE_L10N = True
 | 
			
		||||
 | 
			
		||||
USE_TZ = True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Static files (CSS, JavaScript, Images)
 | 
			
		||||
# https://docs.djangoproject.com/en/3.0/howto/static-files/
 | 
			
		||||
 | 
			
		||||
STATIC_URL = '/static/'
 | 
			
		||||
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
 | 
			
		||||
STATICFILES_DIRS = [
 | 
			
		||||
    os.path.join(BASE_DIR, "static"),
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# E-mail
 | 
			
		||||
DEFAULT_FROM_EMAIL = os.environ.get('EMAIL_FROM')
 | 
			
		||||
EMAIL_HOST = os.environ.get('EMAIL_HOST')
 | 
			
		||||
EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER')
 | 
			
		||||
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD')
 | 
			
		||||
EMAIL_PORT = os.environ.get('EMAIL_PORT', default=465)
 | 
			
		||||
EMAIL_USE_SSL = int(os.environ.get('EMAIL_USE_SSL', default=1))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Celery
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,6 +17,8 @@ from django.contrib import admin
 | 
			
		|||
from django.urls import include, path
 | 
			
		||||
 | 
			
		||||
urlpatterns = [
 | 
			
		||||
    path('accounts/', include('django_registration.backends.activation.urls')),
 | 
			
		||||
    path('accounts/', include('django.contrib.auth.urls')),
 | 
			
		||||
    path('admin/', admin.site.urls),
 | 
			
		||||
    path('rtmp/', include('rtmp.urls')),
 | 
			
		||||
    path('concierge/', include('concierge.urls')),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
django>=3.0
 | 
			
		||||
django-registration>=3.1
 | 
			
		||||
django-bootstrap4
 | 
			
		||||
django-fa
 | 
			
		||||
celery>=4.4
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,5 +11,8 @@ class RestreamConfig(models.Model):
 | 
			
		|||
    name = models.CharField(max_length=100)
 | 
			
		||||
    active = models.BooleanField()
 | 
			
		||||
 | 
			
		||||
    def class_name(self):
 | 
			
		||||
        return self.__class__.__name__
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        return '{} to {}'.format(self.stream, self.name)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
from django.db import models
 | 
			
		||||
from django.urls import reverse
 | 
			
		||||
from django.utils.translation import gettext as _
 | 
			
		||||
import uuid
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -8,6 +9,9 @@ from . import signals
 | 
			
		|||
class Application(models.Model):
 | 
			
		||||
    name = models.CharField(max_length=100, unique=True, help_text=_("rtmp_application_name"))
 | 
			
		||||
 | 
			
		||||
    def class_name(self):
 | 
			
		||||
        return self.__class__.__name__
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        return self.name
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -50,5 +54,11 @@ class Stream(models.Model):
 | 
			
		|||
                                         )
 | 
			
		||||
        self.save()
 | 
			
		||||
 | 
			
		||||
    def get_absolute_url(self):
 | 
			
		||||
        return reverse('rtmp:stream_detail', kwargs={'pk': self.pk})
 | 
			
		||||
 | 
			
		||||
    def class_name(self):
 | 
			
		||||
        return self.__class__.__name__
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        return self.name
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,44 @@
 | 
			
		|||
{% extends 'base.html' %}
 | 
			
		||||
{% load bootstrap4 %}
 | 
			
		||||
{% load font_awesome %}
 | 
			
		||||
{% block 'content' %}
 | 
			
		||||
  <h6>Create new stream configuration</h6>
 | 
			
		||||
  <hr class="my-4">
 | 
			
		||||
<div class="row">
 | 
			
		||||
  <div class="col-sm border-right">
 | 
			
		||||
    <form method="post">
 | 
			
		||||
      {% csrf_token %}
 | 
			
		||||
      <div class="alert alert-warning" role="alert">
 | 
			
		||||
        When deleting a Stream configuration, you will also delete all other configurations that depend on this stream!
 | 
			
		||||
      </div>
 | 
			
		||||
      <p>Are you sure you want to delete the Stream configuration "{{ object }}"?</p>
 | 
			
		||||
      {% buttons %}
 | 
			
		||||
        <button type="submit" class="btn btn-danger" value="login">
 | 
			
		||||
          {% fa 'trash' %} Delete
 | 
			
		||||
        </button>
 | 
			
		||||
      {% endbuttons %}
 | 
			
		||||
      <input type="hidden" name="next" value="{{ next }}">
 | 
			
		||||
    </form>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="col-sm">
 | 
			
		||||
    <h5>Deleting configurations</h5>
 | 
			
		||||
    <ul>
 | 
			
		||||
      {% for object in to_delete %}
 | 
			
		||||
      {% if object.name %}
 | 
			
		||||
      <li>
 | 
			
		||||
        <strong>{{ object.name }}</strong> - <span>{{ object.class_name }}</span>
 | 
			
		||||
      </li>
 | 
			
		||||
      {% else %}
 | 
			
		||||
      <ul>
 | 
			
		||||
        {% for nested_object in object %}
 | 
			
		||||
        <li>
 | 
			
		||||
          <strong>{{ nested_object.name }}</strong> - <span>{{ nested_object.class_name }}</span>
 | 
			
		||||
        </li>
 | 
			
		||||
        {% endfor %}
 | 
			
		||||
      </ul>
 | 
			
		||||
      {% endif %}
 | 
			
		||||
      {% endfor %}
 | 
			
		||||
    </ul>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,71 @@
 | 
			
		|||
{% extends 'base.html' %}
 | 
			
		||||
{% load bootstrap4 %}
 | 
			
		||||
{% load font_awesome %}
 | 
			
		||||
{% block 'content' %}
 | 
			
		||||
  <h6>Show stream configuration details</h6>
 | 
			
		||||
  <hr class="my-4">
 | 
			
		||||
<div class="row">
 | 
			
		||||
  <div class="col-sm border-right">
 | 
			
		||||
    <dl class="row">
 | 
			
		||||
      <dt class="col-sm-3">Name</dt>
 | 
			
		||||
      <dd class="col-sm-9">{{ object.name }}</dd>
 | 
			
		||||
      <dt class="col-sm-3">Application</dt>
 | 
			
		||||
      <dd class="col-sm-9">{{ object.application }}</dd>
 | 
			
		||||
    </dl>
 | 
			
		||||
    <p><strong>Do not share the stream ID.</strong> It serves as a secret key, and anyone that knows this key could send content to your stream.</p>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="col-sm">
 | 
			
		||||
    <h6>How to configure your Encoder</h6>
 | 
			
		||||
    <hr class="my-4">
 | 
			
		||||
    <p>Set the following <strong>stream server</strong> in your encoder application:</p>
 | 
			
		||||
    <code>rtmp://TODO TODO SERVER BASE URL/{{ object.application }}/</code>
 | 
			
		||||
    <p>Set the following <strong>stream ID</strong> in your encoder application:</p>
 | 
			
		||||
    <div class="input-group mb-4" id="show_hide_stream_key">
 | 
			
		||||
      <input class="form-control" type="password" value="{{ object.stream }}">
 | 
			
		||||
      <div class="input-group-append">
 | 
			
		||||
        <a href="" class="btn btn-outline-secondary"><i class="fa fa-eye-slash" aria-hidden="true"></i></a>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <p>You may need to use the full URL instead:</p>
 | 
			
		||||
    <div class="input-group mb-4" id="show_hide_stream_url">
 | 
			
		||||
      <input class="form-control" type="password" value="rtmp://TODO TODO TODO SERVER BASE URL/{{ object.stream }}">
 | 
			
		||||
      <div class="input-group-append">
 | 
			
		||||
        <a href="" class="btn btn-outline-secondary"><i class="fa fa-eye-slash" aria-hidden="true"></i></a>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
<script>
 | 
			
		||||
  $(function () {
 | 
			
		||||
    $('[data-toggle="popover"]').popover()
 | 
			
		||||
  })
 | 
			
		||||
  $(function() {
 | 
			
		||||
    $("#show_hide_stream_key a").on('click', function(event) {
 | 
			
		||||
        event.preventDefault();
 | 
			
		||||
        if ($('#show_hide_stream_key input').attr('type') == 'text') {
 | 
			
		||||
            $('#show_hide_stream_key input').attr('type', 'password');
 | 
			
		||||
            $('#show_hide_stream_key i').addClass('fa-eye-slash');
 | 
			
		||||
            $('#show_hide_stream_key i').removeClass('fa-eye');
 | 
			
		||||
        } else if ($('#show_hide_stream_key input').attr('type') == 'password') {
 | 
			
		||||
            $('#show_hide_stream_key input').attr('type', 'text');
 | 
			
		||||
            $('#show_hide_stream_key i').removeClass('fa-eye-slash');
 | 
			
		||||
            $('#show_hide_stream_key i').addClass('fa-eye');
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
  $(function() {
 | 
			
		||||
    $("#show_hide_stream_url a").on('click', function(event) {
 | 
			
		||||
        event.preventDefault();
 | 
			
		||||
        if ($('#show_hide_stream_url input').attr('type') == 'text') {
 | 
			
		||||
            $('#show_hide_stream_url input').attr('type', 'password');
 | 
			
		||||
            $('#show_hide_stream_url i').addClass('fa-eye-slash');
 | 
			
		||||
            $('#show_hide_stream_url i').removeClass('fa-eye');
 | 
			
		||||
        } else if ($('#show_hide_stream_url input').attr('type') == 'password') {
 | 
			
		||||
            $('#show_hide_stream_url input').attr('type', 'text');
 | 
			
		||||
            $('#show_hide_stream_url i').removeClass('fa-eye-slash');
 | 
			
		||||
            $('#show_hide_stream_url i').addClass('fa-eye');
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
</script>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,23 @@
 | 
			
		|||
{% extends 'base.html' %}
 | 
			
		||||
{% load bootstrap4 %}
 | 
			
		||||
{% block 'content' %}
 | 
			
		||||
  <h6>Create new stream configuration</h6>
 | 
			
		||||
  <hr class="my-4">
 | 
			
		||||
<div class="row">
 | 
			
		||||
  <div class="col-sm border-right">
 | 
			
		||||
    <form method="post">
 | 
			
		||||
      {% csrf_token %}
 | 
			
		||||
      {% bootstrap_form form %}
 | 
			
		||||
      {% buttons %}
 | 
			
		||||
        <button type="submit" class="btn btn-primary" value="login">
 | 
			
		||||
          Submit
 | 
			
		||||
        </button>
 | 
			
		||||
      {% endbuttons %}
 | 
			
		||||
      <input type="hidden" name="next" value="{{ next }}">
 | 
			
		||||
    </form>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="col-sm">
 | 
			
		||||
    <p>Enter a descriptive name, and select one of the applications.</p>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,38 @@
 | 
			
		|||
{% extends 'base.html' %}
 | 
			
		||||
{% load bootstrap4 %}
 | 
			
		||||
{% load font_awesome %}
 | 
			
		||||
{% block 'content' %}
 | 
			
		||||
  <h6>Stream configurations</h6>
 | 
			
		||||
  <hr class="my-4">
 | 
			
		||||
  <div class="btn-toolbar mb-4" role="toolbar">
 | 
			
		||||
    <div class="btn-group" role="group">
 | 
			
		||||
      <a href="{% url 'rtmp:stream_create' %}" type="button" class="btn btn-sm btn-outline-success">{% fa 'plus' %} Create</a>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
  <table class="table">
 | 
			
		||||
    <thead class="thead-dark">
 | 
			
		||||
      <tr>
 | 
			
		||||
        <th scope="col">Name</th>
 | 
			
		||||
        <th scope="col" class="text-right">Actions</th>
 | 
			
		||||
      </tr>
 | 
			
		||||
    </thead>
 | 
			
		||||
    <tbody>
 | 
			
		||||
      {% for object in object_list %}
 | 
			
		||||
      <tr>
 | 
			
		||||
        <th scope="ro">{{ object.name }}</th>
 | 
			
		||||
        <td align="right">
 | 
			
		||||
          <div class="btn-group" role="group" aria-label="Basic example">
 | 
			
		||||
          <a href="{% url 'rtmp:stream_detail' pk=object.pk %}" type="button" class="btn btn-sm btn-primary">Details</a>
 | 
			
		||||
          <a href="{% url 'rtmp:stream_delete' pk=object.pk %}" type="button" class="btn btn-sm btn-danger">{% fa 'trash' %}</a>
 | 
			
		||||
          </div>
 | 
			
		||||
        </td>
 | 
			
		||||
      </tr>
 | 
			
		||||
      {% endfor %}
 | 
			
		||||
    </tbody>
 | 
			
		||||
  </table>
 | 
			
		||||
  <script>
 | 
			
		||||
    $(function () {
 | 
			
		||||
      $('[data-toggle="popover"]').popover()
 | 
			
		||||
    })
 | 
			
		||||
  </script>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,12 @@
 | 
			
		|||
from django.urls import path
 | 
			
		||||
from . import views
 | 
			
		||||
 | 
			
		||||
app_name = 'rtmp'
 | 
			
		||||
 | 
			
		||||
urlpatterns = [
 | 
			
		||||
    path('callback/srs', views.callback_srs, name='callback_srs'),
 | 
			
		||||
    path('streams/', views.StreamList.as_view(), name='stream_list'),
 | 
			
		||||
    path('streams/<int:pk>/', views.StreamDetail.as_view(), name='stream_detail'),
 | 
			
		||||
    path('streams/<int:pk>/delete', views.StreamDelete.as_view(), name='stream_delete'),
 | 
			
		||||
    path('streams/create', views.StreamCreate.as_view(), name='stream_create'),
 | 
			
		||||
]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,14 @@
 | 
			
		|||
import json
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
from django.http import HttpResponse
 | 
			
		||||
from django.views.decorators.csrf import csrf_exempt
 | 
			
		||||
from django.core.exceptions import ObjectDoesNotExist
 | 
			
		||||
from django.http import HttpResponse
 | 
			
		||||
from django.urls import reverse_lazy
 | 
			
		||||
from django.contrib.auth.decorators import login_required
 | 
			
		||||
from django.contrib.admin.utils import NestedObjects
 | 
			
		||||
from django.utils.decorators import method_decorator
 | 
			
		||||
from django.views.decorators.csrf import csrf_exempt
 | 
			
		||||
from django.views.generic import ListView, DetailView, CreateView, DeleteView
 | 
			
		||||
 | 
			
		||||
from . import models
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -40,3 +45,36 @@ def callback_srs(request):
 | 
			
		|||
        stream.on_unpublish(param=param)
 | 
			
		||||
 | 
			
		||||
    return HttpResponse('0')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@method_decorator(login_required, name='dispatch')
 | 
			
		||||
class StreamList(ListView):
 | 
			
		||||
    model = models.Stream
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@method_decorator(login_required, name='dispatch')
 | 
			
		||||
class StreamDetail(DetailView):
 | 
			
		||||
    model = models.Stream
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@method_decorator(login_required, name='dispatch')
 | 
			
		||||
class StreamCreate(CreateView):
 | 
			
		||||
    model = models.Stream
 | 
			
		||||
    fields = ["name", "application"]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@method_decorator(login_required, name='dispatch')
 | 
			
		||||
class StreamDelete(DeleteView):
 | 
			
		||||
    model = models.Stream
 | 
			
		||||
    success_url = reverse_lazy('rtmp:stream_list')
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        context = super().get_context_data(**kwargs)
 | 
			
		||||
 | 
			
		||||
        collector = NestedObjects(using='default')
 | 
			
		||||
        collector.collect([self.object])
 | 
			
		||||
 | 
			
		||||
        context['to_delete'] = collector.nested()
 | 
			
		||||
 | 
			
		||||
        print(context['to_delete'])
 | 
			
		||||
        return context
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
{% load static %}
 | 
			
		||||
{% load bootstrap4 %}
 | 
			
		||||
{% load font_awesome %}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -6,7 +7,7 @@
 | 
			
		|||
  <head>
 | 
			
		||||
    <meta charset="utf-8" />
 | 
			
		||||
    <meta http-equiv="x-ua-compatible" content="ie=edge" />
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1" />
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
 | 
			
		||||
 | 
			
		||||
    <title>{% block 'title' %}portier{% endblock %}</title>
 | 
			
		||||
    {% bootstrap_css %}
 | 
			
		||||
| 
						 | 
				
			
			@ -15,8 +16,51 @@
 | 
			
		|||
  </head>
 | 
			
		||||
 | 
			
		||||
  <body>
 | 
			
		||||
    {% bootstrap_messages %}
 | 
			
		||||
    {% block 'body' %}
 | 
			
		||||
    <header>
 | 
			
		||||
      <nav class="navbar navbar-expand-md navbar-light bg-light mb-4 border boder-bottom-0">
 | 
			
		||||
        <span class="navbar-brand mb-0 h1">
 | 
			
		||||
          <a href="{% url 'index' %}">Portier</a>
 | 
			
		||||
        </span>
 | 
			
		||||
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
 | 
			
		||||
          <span class="navbar-toggler-icon"></span>
 | 
			
		||||
        </button>
 | 
			
		||||
 | 
			
		||||
        <div class="collapse navbar-collapse" id="navbarSupportedContent">
 | 
			
		||||
          <ul class="navbar-nav mr-auto">
 | 
			
		||||
          </ul>
 | 
			
		||||
          <ul class="navbar-nav">
 | 
			
		||||
          {% if user.is_authenticated %}
 | 
			
		||||
            <li class="nav-item dropdown">
 | 
			
		||||
              <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
 | 
			
		||||
                Configuration
 | 
			
		||||
              </a>
 | 
			
		||||
              <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
 | 
			
		||||
                <a class="dropdown-item" href="#">Something else here</a>
 | 
			
		||||
                <div class="dropdown-divider"></div>
 | 
			
		||||
                <h6 class="dropdown-header">Streaming</h6>
 | 
			
		||||
                <a class="dropdown-item" href="{% url 'rtmp:stream_list' %}">Streams</a>
 | 
			
		||||
                <a class="dropdown-item" href="#">Restream</a>
 | 
			
		||||
              </div>
 | 
			
		||||
            </li>
 | 
			
		||||
          {% endif %}
 | 
			
		||||
            <li class="nav-item">
 | 
			
		||||
          {% if user.is_authenticated %}
 | 
			
		||||
              <a class="nav-link logout" href="{% url 'logout' %}?next={% url 'index' %}">Logout</a>
 | 
			
		||||
          {% else %}
 | 
			
		||||
              <a class="nav-link login" href="{% url 'login' %}?next={% url 'index' %}">Login</a>
 | 
			
		||||
          {% endif %}
 | 
			
		||||
            </li>
 | 
			
		||||
          </ul>
 | 
			
		||||
        </div>
 | 
			
		||||
      </nav>
 | 
			
		||||
    </header>
 | 
			
		||||
    <main class="container" roles="main">
 | 
			
		||||
    {% block 'content' %}
 | 
			
		||||
    {% endblock %}
 | 
			
		||||
    </main>
 | 
			
		||||
    <footer class="text-muted">
 | 
			
		||||
      <div class="container">
 | 
			
		||||
      </div>
 | 
			
		||||
    </footer>
 | 
			
		||||
  </body>
 | 
			
		||||
</html>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
{% extends 'base.html' %}
 | 
			
		||||
{% load bootstrap4 %}
 | 
			
		||||
{% block 'content' %}
 | 
			
		||||
  <h1>Login</h1>
 | 
			
		||||
<div class="row">
 | 
			
		||||
  <div class="col-sm border-right">
 | 
			
		||||
    <form method="post">
 | 
			
		||||
      {% csrf_token %}
 | 
			
		||||
      {% bootstrap_form form %}
 | 
			
		||||
      {% buttons %}
 | 
			
		||||
        <button type="submit" class="btn btn-primary" value="login">
 | 
			
		||||
          Submit
 | 
			
		||||
        </button>
 | 
			
		||||
      {% endbuttons %}
 | 
			
		||||
      <input type="hidden" name="next" value="{{ next }}">
 | 
			
		||||
    </form>
 | 
			
		||||
    <p><a href="{% url 'password_reset' %}">Lost password?</a></p>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="col-sm">
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
{% extends 'base.html' %}
 | 
			
		||||
{% load bootstrap4 %}
 | 
			
		||||
{% block 'content' %}
 | 
			
		||||
<h1>Password Change</h1>
 | 
			
		||||
<p>It frickin' worked! OMG.</p>
 | 
			
		||||
<a class="btn btn-primary btn-lg" href="{% url 'index' %}">Back to safety</a>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
{% extends 'base.html' %}
 | 
			
		||||
{% load bootstrap4 %}
 | 
			
		||||
{% block 'content' %}
 | 
			
		||||
  <h1>Password Change</h1>
 | 
			
		||||
<div class="row">
 | 
			
		||||
  <div class="col-sm border-right">
 | 
			
		||||
    <form method="post">
 | 
			
		||||
      {% csrf_token %}
 | 
			
		||||
      {% bootstrap_form form %}
 | 
			
		||||
      {% buttons %}
 | 
			
		||||
        <button type="submit" class="btn btn-primary" value="login">
 | 
			
		||||
          Submit
 | 
			
		||||
        </button>
 | 
			
		||||
      {% endbuttons %}
 | 
			
		||||
      <input type="hidden" name="next" value="{{ next }}">
 | 
			
		||||
    </form>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="col-sm">
 | 
			
		||||
    <p>Please enter a name for your new stream configuration. This is only used for identification purposes.</p>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
{% extends 'base.html' %}
 | 
			
		||||
{% load bootstrap4 %}
 | 
			
		||||
{% block 'content' %}
 | 
			
		||||
  <h1>Password Reset</h1>
 | 
			
		||||
<div class="row">
 | 
			
		||||
  <div class="col-sm border-right">
 | 
			
		||||
    <form method="post">
 | 
			
		||||
      {% csrf_token %}
 | 
			
		||||
      {% bootstrap_form form %}
 | 
			
		||||
      {% buttons %}
 | 
			
		||||
        <button type="submit" class="btn btn-primary" value="login">
 | 
			
		||||
          Submit
 | 
			
		||||
        </button>
 | 
			
		||||
      {% endbuttons %}
 | 
			
		||||
      <input type="hidden" name="next" value="{{ next }}">
 | 
			
		||||
    </form>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="col-sm">
 | 
			
		||||
    <p>Forgotten your password? Enter your email address, and we’ll email instructions for setting a new one.</p>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
		Loading…
	
		Reference in New Issue