Added docker support

This commit is contained in:
Jett Jackson
2018-10-30 14:15:49 +08:00
parent 97e7e792f8
commit 84b0c2e861
108 changed files with 240 additions and 16 deletions

View File

@ -0,0 +1,21 @@
{% extends 'YtManagerApp/controls/modal.html' %}
{% load crispy_forms_tags %}
{% block modal_title %}
New folder
{% endblock modal_title %}
{% block modal_content %}
<form action="{% url 'modal_create_folder' %}" method="post">
{{ block.super }}
</form>
{% endblock %}
{% block modal_body %}
{% crispy form %}
{% endblock modal_body %}
{% block modal_footer %}
<input class="btn btn-primary" type="submit" value="Create">
<input class="btn btn-secondary" type="button" value="Cancel" data-dismiss="modal" aria-label="Cancel">
{% endblock modal_footer %}

View File

@ -0,0 +1,23 @@
{% extends 'YtManagerApp/controls/modal.html' %}
{% load crispy_forms_tags %}
{% block modal_title %}
Delete folder
{% endblock modal_title %}
{% block modal_content %}
<form action="{% url 'modal_delete_folder' object.id %}" method="post">
{% csrf_token %}
{{ block.super }}
</form>
{% endblock %}
{% block modal_body %}
<p>Are you sure you want to delete folder &quot;{{ object }}&quot; and all its subfolders?</p>
{{ form | crispy }}
{% endblock modal_body %}
{% block modal_footer %}
<input class="btn btn-danger" type="submit" value="Delete" aria-label="Delete">
<input class="btn btn-secondary" type="button" value="Cancel" data-dismiss="modal" aria-label="Cancel">
{% endblock modal_footer %}

View File

@ -0,0 +1,21 @@
{% extends 'YtManagerApp/controls/modal.html' %}
{% load crispy_forms_tags %}
{% block modal_title %}
Edit folder
{% endblock modal_title %}
{% block modal_content %}
<form action="{% url 'modal_update_folder' form.instance.pk %}" method="post">
{{ block.super }}
</form>
{% endblock %}
{% block modal_body %}
{% crispy form %}
{% endblock modal_body %}
{% block modal_footer %}
<input class="btn btn-primary" type="submit" value="Save" aria-label="Save">
<input class="btn btn-secondary" type="button" value="Cancel" data-dismiss="modal" aria-label="Cancel">
{% endblock modal_footer %}

View File

@ -0,0 +1,43 @@
{% block modal_stylesheets %}
{% endblock %}
<div id="{{ modal_id }}" class="modal {{ modal_classes }}" tabindex="-1" role="dialog">
<div class="modal-dialog {{ modal_dialog_classes }}" role="document">
<div class="modal-content">
{% block modal_content %}
{% block modal_header_wrapper %}
<div class="modal-header">
{% block modal_header %}
<h5 id="{{ modal_id }}_Title" class="modal-title">
{% block modal_title %}{{ modal_title }}{% endblock modal_title %}
</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
{% endblock modal_header %}
</div>
{% endblock modal_header_wrapper %}
{% block modal_body_wrapper %}
<div class="modal-body">
{% block modal_body %}
{% endblock %}
</div>
{% endblock modal_body_wrapper %}
{% block modal_footer_wrapper %}
<div class="modal-footer">
<div id="modal-loading-ring" class="loading-dual-ring-small mr-auto" style="display: none;"></div>
{% block modal_footer %}
{% endblock modal_footer %}
</div>
{% endblock modal_footer_wrapper %}
{% endblock modal_content %}
</div>
</div>
</div>
{% block modal_scripts %}
{% endblock %}

View File

@ -0,0 +1,21 @@
{% extends 'YtManagerApp/controls/modal.html' %}
{% load crispy_forms_tags %}
{% block modal_title %}
New subscription
{% endblock modal_title %}
{% block modal_content %}
<form action="{% url 'modal_create_subscription' %}" method="post">
{{ block.super }}
</form>
{% endblock %}
{% block modal_body %}
{% crispy form %}
{% endblock modal_body %}
{% block modal_footer %}
<input class="btn btn-primary" type="submit" value="Create">
<input class="btn btn-secondary" type="button" value="Cancel" data-dismiss="modal" aria-label="Cancel">
{% endblock modal_footer %}

View File

@ -0,0 +1,23 @@
{% extends 'YtManagerApp/controls/modal.html' %}
{% load crispy_forms_tags %}
{% block modal_title %}
Delete subscription
{% endblock modal_title %}
{% block modal_content %}
<form action="{% url 'modal_delete_subscription' object.id %}" method="post">
{% csrf_token %}
{{ block.super }}
</form>
{% endblock %}
{% block modal_body %}
<p>Are you sure you want to delete subscription &quot;{{ object }}&quot;?</p>
{{ form | crispy }}
{% endblock modal_body %}
{% block modal_footer %}
<input class="btn btn-danger" type="submit" value="Delete" aria-label="Delete">
<input class="btn btn-secondary" type="button" value="Cancel" data-dismiss="modal" aria-label="Cancel">
{% endblock modal_footer %}

View File

@ -0,0 +1,21 @@
{% extends 'YtManagerApp/controls/modal.html' %}
{% load crispy_forms_tags %}
{% block modal_title %}
Edit subscription
{% endblock modal_title %}
{% block modal_content %}
<form action="{% url 'modal_update_subscription' form.instance.pk %}" method="post">
{{ block.super }}
</form>
{% endblock %}
{% block modal_body %}
{% crispy form %}
{% endblock modal_body %}
{% block modal_footer %}
<input class="btn btn-primary" type="submit" value="Save" aria-label="Save">
<input class="btn btn-secondary" type="button" value="Cancel" data-dismiss="modal" aria-label="Cancel">
{% endblock modal_footer %}

View File

@ -0,0 +1,74 @@
{% extends "YtManagerApp/master_default.html" %}
{% load static %}
{% load crispy_forms_tags %}
{% block stylesheets %}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css" />
{% endblock %}
{% block scripts %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js"></script>
<script>
{% include 'YtManagerApp/js/index.js' %}
</script>
{% endblock %}
{% block body %}
<div id="modal-wrapper">
<div id="modal-loading" class="black-overlay">
<div class="loading-dual-ring loading-dual-ring-center-screen"></div>
</div>
<div id="modal-wrapper">
</div>
</div>
<div class="row">
<div class="col-3">
{# Tree toolbar #}
<div class="btn-toolbar" role="toolbar" aria-label="Subscriptions toolbar">
<div class="btn-group btn-group-sm mr-2" role="group">
<button id="btn_create_sub" type="button" class="btn btn-secondary" >
<span class="typcn typcn-plus" aria-hidden="true"></span>
</button>
<button id="btn_create_folder" type="button" class="btn btn-secondary">
<span class="typcn typcn-folder-add" aria-hidden="true"></span>
</button>
</div>
<div class="btn-group btn-group-sm mr-2" role="group">
<button id="btn_edit_node" type="button" class="btn btn-secondary" >
<span class="typcn typcn-edit" aria-hidden="true"></span>
</button>
<button id="btn_delete_node" type="button" class="btn btn-secondary" >
<span class="typcn typcn-trash" aria-hidden="true"></span>
</button>
</div>
</div>
<div id="tree-wrapper">
<div class="d-flex">
<div class="loading-dual-ring mx-auto my-5"></div>
</div>
</div>
</div>
<div class="col-9">
{# Video toolbar #}
<div class="btn-toolbar" role="toolbar" aria-label="Subscriptions toolbar">
{% crispy filter_form %}
</div>
<div id="videos-wrapper">
</div>
<div id="videos-loading" style="display: none">
<div class="d-flex">
<div class="loading-dual-ring mx-auto my-5"></div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,9 @@
{% extends "YtManagerApp/master_default.html" %}
{% load static %}
{% block body %}
<h1>Hello</h1>
<h2>Please log in to continue</h2>
{% endblock %}

View File

@ -0,0 +1,61 @@
{% load humanize %}
{% load ratings %}
<div class="video-gallery container-fluid">
<div class="row">
{% for video in videos %}
<div class="card-wrapper col-12 col-sm-6 col-lg-4 col-xl-3 d-flex align-items-stretch">
<div class="card mx-auto">
<img class="card-img-top" src="{{ video.icon_best }}" alt="Thumbnail">
<div class="card-body">
<h5 class="card-title">
{% if not video.watched %}
<sup class="badge badge-primary">New</sup>
{% endif %}
{{ video.name }}
</h5>
<p class="card-text small text-muted">
<span>{{ video.views | intcomma }} views</span>
<span>&#x2022;</span>
<span>{{ video.publish_date | naturaltime }}</span>
</p>
<p class="card-text">{{ video.description | truncatechars:120 }}</p>
</div>
<div class="card-footer dropdown show">
<span class="typcn typcn-eye {{ video.watched | yesno:"video-icon-yes,video-icon-no" }}"
title="{{ video.watched | yesno:"Watched,Not watched" }}"></span>
<span class="typcn typcn-download {{ video.downloaded_path | yesno:"video-icon-yes,,video-icon-no" }}"
title="{{ video.downloaded_path | yesno:"Downloaded,,Not downloaded" }}"></span>
<small class="text-muted">{{ video.publish_date }}</small>
<a class="card-more float-right text-muted"
href="#" role="button" id="dropdownMenuLink"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="typcn typcn-cog"></span>
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
{% if video.watched %}
<a class="dropdown-item ajax-link" href="#" data-post-url="{% url 'ajax_action_mark_video_unwatched' video.id %}">
Mark not watched
</a>
{% else %}
<a class="dropdown-item ajax-link" href="#" data-post-url="{% url 'ajax_action_mark_video_watched' video.id %}">
Mark watched
</a>
{% endif %}
{% if video.downloaded_path %}
<a class="dropdown-item ajax-link" href="#" data-post-url="{% url 'ajax_action_delete_video_files' video.id %}">
Delete downloaded
</a>
{% else %}
<a class="dropdown-item ajax-link" href="#" data-post-url="{% url 'ajax_action_download_video_files' video.id %}" >
Download
</a>
{% endif %}
</div>
</div>
</div>
</div>
{% endfor %}
</div>
</div>

View File

@ -0,0 +1,185 @@
class AjaxModal
{
constructor(url)
{
this.wrapper = $("#modal-wrapper");
this.loading = $("#modal-loading");
this.url = url;
this.modal = null;
this.form = null;
this.submitCallback = null;
this.modalLoadingRing = null;
}
setSubmitCallback(callback) {
this.submitCallback = callback;
}
_showLoading() {
this.loading.fadeIn(500);
}
_hideLoading() {
this.loading.fadeOut(100);
}
_showModal() {
if (this.modal != null)
this.modal.modal();
}
_hideModal() {
if (this.modal != null)
this.modal.modal('hide');
}
_load(result) {
this.wrapper.html(result);
this.modal = this.wrapper.find('.modal');
this.form = this.wrapper.find('form');
this.modalLoadingRing = this.wrapper.find('#modal-loading-ring');
let pThis = this;
this.form.submit(function(e) {
pThis._submit(e);
})
}
_loadFailed() {
this.wrapper.html('<div class="alert alert-danger">An error occurred while displaying the dialog!</div>');
}
_submit(e) {
let pThis = this;
let url = this.form.attr('action');
$.post(url, this.form.serialize())
.done(function(result) {
pThis._submitDone(result);
})
.fail(function() {
pThis._submitFailed();
})
.always(function() {
pThis.modalLoadingRing.fadeOut(100);
pThis.wrapper.find(":input").prop("disabled", false);
});
this.modalLoadingRing.fadeIn(200);
this.wrapper.find(":input").prop("disabled", true);
e.preventDefault();
}
_submitDone(result) {
// Clear old errors first
this.form.find('.modal-field-error').remove();
if (!result.hasOwnProperty('success')) {
this._submitInvalidResponse();
return;
}
if (result.success) {
this._hideModal();
if (this.submitCallback != null)
this.submitCallback();
}
else {
if (!result.hasOwnProperty('errors')) {
this._submitInvalidResponse();
return;
}
for (let field in result.errors)
if (result.errors.hasOwnProperty(field))
{
let errorsArray = result.errors[field];
let errorsConcat = "<div class=\"alert alert-danger modal-field-error\"><ul>";
for(let error of errorsArray) {
errorsConcat += `<li>${error.message}</li>`;
}
errorsConcat += '</ul></div>';
if (field === '__all__')
this.form.find('.modal-body').append(errorsConcat);
else
this.form.find(`[name='${field}']`).after(errorsConcat);
}
let errorsHtml = '';
let err = this.modal.find('#__modal_error');
if (err.length) {
err.html('An error occurred');
}
else {
this.modal.find('.modal-body').append(errorsHtml)
}
}
}
_submitFailed() {
// Clear old errors first
this.form.find('.modal-field-error').remove();
this.form.find('.modal-body')
.append(`<div class="alert alert-danger modal-field-error">An error occurred while processing request!</div>`);
}
_submitInvalidResponse() {
// Clear old errors first
this.form.find('.modal-field-error').remove();
this.form.find('.modal-body')
.append(`<div class="alert alert-danger modal-field-error">Invalid server response!</div>`);
}
loadAndShow()
{
let pThis = this;
this._showLoading();
$.get(this.url)
.done(function (result) {
pThis._load(result);
pThis._showModal();
})
.fail(function () {
pThis._loadFailed();
})
.always(function() {
pThis._hideLoading();
});
}
}
function syncNow() {
$.post("{% url 'ajax_action_sync_now' %}", {
csrfmiddlewaretoken: '{{ csrf_token }}'
});
}
function ajaxLink_Clicked() {
let url_post = $(this).data('post-url');
let url_get = $(this).data('get-url');
if (url_post != null) {
$.post(url_post, {
csrfmiddlewaretoken: '{{ csrf_token }}'
});
}
else if (url_get != null) {
$.get(url_get, {
csrfmiddlewaretoken: '{{ csrf_token }}'
});
}
}
///
/// Initialization
///
$(document).ready(function ()
{
$(".ajax-link").on("click", ajaxLink_Clicked);
$("#btn_sync_now").on("click", syncNow);
});

View File

@ -0,0 +1,189 @@
function treeNode_Edit()
{
let selectedNodes = $("#tree-wrapper").jstree('get_selected', true);
if (selectedNodes.length === 1)
{
let node = selectedNodes[0];
if (node.type === 'folder') {
let id = node.id.replace('folder', '');
let modal = new AjaxModal("{% url 'modal_update_folder' 98765 %}".replace('98765', id));
modal.setSubmitCallback(tree_Refresh);
modal.loadAndShow();
}
else {
let id = node.id.replace('sub', '');
let modal = new AjaxModal("{% url 'modal_update_subscription' 98765 %}".replace('98765', id));
modal.setSubmitCallback(tree_Refresh);
modal.loadAndShow();
}
}
}
function treeNode_Delete()
{
let selectedNodes = $("#tree-wrapper").jstree('get_selected', true);
if (selectedNodes.length === 1)
{
let node = selectedNodes[0];
if (node.type === 'folder') {
let id = node.id.replace('folder', '');
let modal = new AjaxModal("{% url 'modal_delete_folder' 98765 %}".replace('98765', id));
modal.setSubmitCallback(tree_Refresh);
modal.loadAndShow();
}
else {
let id = node.id.replace('sub', '');
let modal = new AjaxModal("{% url 'modal_delete_subscription' 98765 %}".replace('98765', id));
modal.setSubmitCallback(tree_Refresh);
modal.loadAndShow();
}
}
}
function tree_Initialize()
{
let treeWrapper = $("#tree-wrapper");
treeWrapper.jstree({
core : {
data : {
url : "{% url 'ajax_get_tree' %}"
},
check_callback : tree_ValidateChange,
themes : {
dots : false
},
},
types : {
folder : {
icon : "typcn typcn-folder"
},
sub : {
icon : "typcn typcn-user",
max_depth : 0
}
},
plugins : [ "types", "wholerow", "dnd" ]
});
treeWrapper.on("changed.jstree", tree_OnSelectionChanged);
}
function tree_Refresh()
{
$("#tree-wrapper").jstree("refresh");
}
function tree_ValidateChange(operation, node, parent, position, more)
{
if (more.dnd)
{
// create_node, rename_node, delete_node, move_node and copy_node
if (operation === "copy_node" || operation === "move_node")
{
if (more.ref.type === "sub")
return false;
}
}
return true;
}
function tree_OnSelectionChanged(e, data)
{
let filterForm = $('#form_video_filter');
let filterForm_folderId = filterForm.find('#form_video_filter_folder_id');
let filterForm_subId = filterForm.find('#form_video_filter_subscription_id');
let node = data.instance.get_selected(true)[0];
// Fill folder/sub fields
if (node == null) {
filterForm_folderId.val('');
filterForm_subId.val('');
}
else if (node.type === 'folder') {
let id = node.id.replace('folder', '');
filterForm_folderId.val(id);
filterForm_subId.val('');
}
else {
let id = node.id.replace('sub', '');
filterForm_folderId.val('');
filterForm_subId.val(id);
}
videos_Reload();
}
function videos_Reload()
{
videos_Submit.call($('#form_video_filter'));
}
let videos_timeout = null;
function videos_ReloadWithTimer()
{
clearTimeout(videos_timeout);
videos_timeout = setTimeout(function()
{
videos_Submit.call($('#form_video_filter'));
videos_timeout = null;
}, 200);
}
function videos_Submit(e)
{
let loadingDiv = $('#videos-loading');
loadingDiv.fadeIn(300);
let form = $(this);
let url = form.attr('action');
$.post(url, form.serialize())
.done(function(result) {
$("#videos-wrapper").html(result);
$(".ajax-link").on("click", ajaxLink_Clicked);
})
.fail(function() {
$("#videos-wrapper").html('<div class="alert alert-danger">An error occurred while retrieving the video list!</div>');
})
.always(function() {
loadingDiv.fadeOut(100);
});
if (e != null)
e.preventDefault();
}
///
/// Initialization
///
$(document).ready(function ()
{
tree_Initialize();
// Subscription toolbar
$("#btn_create_sub").on("click", function () {
let modal = new AjaxModal("{% url 'modal_create_subscription' %}");
modal.setSubmitCallback(tree_Refresh);
modal.loadAndShow();
});
$("#btn_create_folder").on("click", function () {
let modal = new AjaxModal("{% url 'modal_create_folder' %}");
modal.setSubmitCallback(tree_Refresh);
modal.loadAndShow();
});
$("#btn_edit_node").on("click", treeNode_Edit);
$("#btn_delete_node").on("click", treeNode_Delete);
// Videos filters
let filters_form = $("#form_video_filter");
filters_form.submit(videos_Submit);
filters_form.find('input[name=query]').on('change', videos_ReloadWithTimer);
filters_form.find('select[name=sort]').on('change', videos_ReloadWithTimer);
filters_form.find('select[name=show_watched]').on('change', videos_ReloadWithTimer);
filters_form.find('select[name=show_downloaded]').on('change', videos_ReloadWithTimer);
videos_Reload();
});

View File

@ -0,0 +1,76 @@
{% load static %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>{% block title %}YouTube Subscription Manager{% endblock %}</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<link rel="stylesheet" href="{% static 'YtManagerApp/import/typicons/typicons.min.css' %}" />
<link rel="stylesheet" href="{% static 'YtManagerApp/css/style.css' %}">
{% block stylesheets %}
{% endblock %}
</head>
<body>
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
<script>
{% include 'YtManagerApp/js/common.js' %}
</script>
{% block scripts %}
{% endblock %}
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="{% url 'home' %}">YouTube Manager</a>
<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 ml-auto">
{% if request.user.is_authenticated %}
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Welcome,
{% if request.user.first_name %}
{{ request.user.first_name }}
{% else %}
{{ request.user.username }}
{% endif %}
</a>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="userDropdown">
<a class="dropdown-item" href="{% url 'settings' %}">Settings</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="{% url 'logout' %}">Log out</a>
</div>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="{% url 'login' %}">Login</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'register' %}">Register</a>
</li>
{% endif %}
</ul>
</div>
</nav>
<div id="main_body" class="container-fluid">
{% block body %}
{% endblock %}
</div>
<footer id="main_footer" class="footer bg-light">
<span class="ml-auto text-muted">Last synchronized: just now</span>
<button id="btn_sync_now" class="btn btn-sm btn-light" title="Synchronize now!">
<span class="typcn typcn-arrow-sync" aria-hidden="true"></span>
</button>
</footer>
</body>
</html>

View File

@ -0,0 +1,12 @@
{% extends "YtManagerApp/master_default.html" %}
{% load crispy_forms_tags %}
{% block body %}
<div class="container">
<h1>Settings</h1>
<p>If no value is set, the server's defaults will be used.</p>
{% crispy form %}
</div>
{% endblock body %}

View File

@ -0,0 +1,27 @@
{% extends 'YtManagerApp/master_default.html' %}
{% load static %}
{% load crispy_forms_tags %}
{% block scripts %}
<script>
window.setTimeout(function(){
window.location.href = "/";
}, 3000);
</script>
{% endblock %}
{% block body %}
<div class="alert-card mx-auto">
<div class="alert alert-info" role="alert">
You have been logged out!
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,44 @@
{% extends 'YtManagerApp/master_default.html' %}
{% load static %}
{% load crispy_forms_tags %}
{% block stylesheets %}
<link rel="stylesheet" href="{% static 'YtManagerApp/css/login.css' %}">
{% endblock %}
{% block body %}
<div class="login-card mx-auto">
{% if next %}
{% if user.is_authenticated %}
<div class="alert alert-warning" role="alert">
Your account doesn't have access to this page. To proceed,
please login with an account that has access.
</div>
{% else %}
<div class="alert alert-info" role="alert">
Please login or register to see this page.
</div>
{% endif %}
{% endif %}
<h5>Login</h5>
<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}"/>
{{ form | crispy }}
<div class="form-group">
<input class="btn btn-primary" type="submit" value="login"/>
<a class="ml-2" href="{% url 'password_reset' %}">Recover password</a>
</div>
</form>
</div>
{% endblock %}

View File

@ -0,0 +1,26 @@
{% extends 'YtManagerApp/master_default.html' %}
{% load static %}
{% load crispy_forms_tags %}
{% block scripts %}
<script>
window.setTimeout(function(){
window.location.href = "/";
}, 5000);
</script>
{% endblock %}
{% block body %}
<div class="alert-card mx-auto">
<div class="alert alert-info" role="alert">
The password has been changed!
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,33 @@
{% extends 'YtManagerApp/master_default.html' %}
{% load static %}
{% load crispy_forms_tags %}
{% block stylesheets %}
<link rel="stylesheet" href="{% static 'YtManagerApp/css/login.css' %}">
{% endblock %}
{% block body %}
{% if validlink %}
<div class="login-card mx-auto">
<h5>Confirm password reset</h5>
<form method="post" action="">
{% csrf_token %}
{{ form | crispy }}
<div class="form-group">
<input class="btn btn-primary" type="submit" value="change password"/>
</div>
</form>
</div>
{% else %}
<div class="alert-card mx-auto">
<div class="alert alert-danger" role="alert">
The password reset link was invalid, possibly because it has already been used. Please request a new password reset.
</div>
</div>
{% endif %}
{% endblock %}

View File

@ -0,0 +1,28 @@
{% extends 'YtManagerApp/master_default.html' %}
{% load static %}
{% load crispy_forms_tags %}
{% block scripts %}
<script>
window.setTimeout(function(){
window.location.href = "/";
}, 10000);
</script>
{% endblock %}
{% block body %}
<div class="alert-card mx-auto">
<div class="alert alert-info" role="alert">
<p>We've emailed you instructions for resetting your password.</p>
<p>If they haven't arrived in a few minutes, check your spam folder.</p>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,2 @@
Someone asked for password reset for email {{ email }}. Follow the link below:
{{ protocol}}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}

View File

@ -0,0 +1,45 @@
{% extends 'YtManagerApp/master_default.html' %}
{% load static %}
{% load crispy_forms_tags %}
{% block stylesheets %}
<link rel="stylesheet" href="{% static 'YtManagerApp/css/login.css' %}">
{% endblock %}
{% block body %}
<div class="login-card mx-auto">
{% if next %}
{% if user.is_authenticated %}
<div class="alert alert-warning" role="alert">
Your account doesn't have access to this page. To proceed,
please login with an account that has access.
</div>
{% else %}
<div class="alert alert-info" role="alert">
Please login or register to see this page.
</div>
{% endif %}
{% endif %}
<h5>Password reset</h5>
<form method="post" action="{% url 'password_reset' %}">
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}"/>
{{ form | crispy }}
<p>If there is any account associated with the given e-mail address,
an e-mail will be sent containing the password reset link.</p>
<div class="form-group">
<input class="btn btn-primary" type="submit" value="reset"/>
</div>
</form>
</div>
{% endblock %}

View File

@ -0,0 +1,38 @@
{% extends 'YtManagerApp/master_default.html' %}
{% load static %}
{% load crispy_forms_tags %}
{% block stylesheets %}
<link rel="stylesheet" href="{% static 'YtManagerApp/css/login.css' %}">
{% endblock %}
{% block body %}
<div class="register-card mx-auto">
{% if next %}
{% if user.is_authenticated %}
<div class="alert alert-warning" role="alert">
Your account doesn't have access to this page. To proceed,
please login with an account that has access.
</div>
{% else %}
<div class="alert alert-info" role="alert">
Please login or register to see this page.
</div>
{% endif %}
{% endif %}
{% if is_first_user %}
<div class="alert alert-info" role="alert">
Since this is the first user to register, it will be the system administrator.
</div>
{% endif %}
<h5>Register</h5>
{% crispy form %}
</div>
{% endblock %}

View File

@ -0,0 +1,27 @@
{% extends 'YtManagerApp/master_default.html' %}
{% load static %}
{% load crispy_forms_tags %}
{% block scripts %}
<script>
window.setTimeout(function(){
window.location.href = "/";
}, 3000);
</script>
{% endblock %}
{% block body %}
<div class="alert-card mx-auto">
<div class="alert alert-info" role="alert">
You have registered successfully!
</div>
</div>
{% endblock %}