initial commit
This commit is contained in:
0
cabinet/__init__.py
Normal file
0
cabinet/__init__.py
Normal file
3
cabinet/admin.py
Normal file
3
cabinet/admin.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
5
cabinet/apps.py
Normal file
5
cabinet/apps.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class CabinetConfig(AppConfig):
|
||||
name = 'cabinet'
|
0
cabinet/migrations/__init__.py
Normal file
0
cabinet/migrations/__init__.py
Normal file
3
cabinet/models.py
Normal file
3
cabinet/models.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
78
cabinet/templates/cabinet/_base.html
Normal file
78
cabinet/templates/cabinet/_base.html
Normal file
@@ -0,0 +1,78 @@
|
||||
{% load staticfiles bootstrap4 cabinet %}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html class="fixed dark" lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<title>{{ title }}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700,800|Shadows+Into+Light" rel="stylesheet" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'vendor/bootstrap/css/bootstrap.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'vendor/animate/animate.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'vendor/font-awesome/css/fontawesome-all.min.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'vendor/magnific-popup/magnific-popup.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'vendor/pnotify/pnotify.custom.css' %}">
|
||||
|
||||
<link rel="stylesheet" href="{% static 'css/theme.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'css/custom.css' %}">
|
||||
|
||||
<script src="{% static 'vendor/modernizr/modernizr.js' %}"></script>
|
||||
<script src="{% static 'vendor/turbolinks/turbolinks.js' %}"></script>
|
||||
</head>
|
||||
<body class="{% if not is_turbolinks %}loading-overlay-showing{% endif %}" data-loading-overlay>
|
||||
<div class="loading-overlay">
|
||||
<div class="bounce-loader">
|
||||
<div class="bounce1"></div>
|
||||
<div class="bounce2"></div>
|
||||
<div class="bounce3"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% block page %}{% endblock %}
|
||||
|
||||
<script data-turbolinks-eval="false" src="{% static 'vendor/jquery/jquery.js' %}"></script>
|
||||
<script data-turbolinks-eval="false" src="{% static 'vendor/jquery-browser-mobile/jquery.browser.mobile.js' %}"></script>
|
||||
<script data-turbolinks-eval="false" src="{% static 'vendor/jquery-cookie/jquery-cookie.js' %}"></script>
|
||||
<script data-turbolinks-eval="false" src="{% static 'vendor/popper/umd/popper.min.js' %}"></script>
|
||||
<script data-turbolinks-eval="false" src="{% static 'vendor/bootstrap/js/bootstrap.js' %}"></script>
|
||||
<script data-turbolinks-eval="false" src="{% static 'vendor/common/common.js' %}"></script>
|
||||
<script data-turbolinks-eval="false" src="{% static 'vendor/nanoscroller/nanoscroller.js' %}"></script>
|
||||
<script data-turbolinks-eval="false" src="{% static 'vendor/magnific-popup/jquery.magnific-popup.js' %}"></script>
|
||||
<script data-turbolinks-eval="false" src="{% static 'vendor/jquery-placeholder/jquery-placeholder.js' %}"></script>
|
||||
<script data-turbolinks-eval="false" src="{% static 'vendor/pnotify/pnotify.custom.js' %}"></script>
|
||||
|
||||
<script data-turbolinks-eval="false" src="{% static 'js/theme.js' %}"></script>
|
||||
<script data-turbolinks-eval="false" src="{% static 'js/custom.js' %}"></script>
|
||||
|
||||
<script src="{% static 'js/theme.init.js' %}"></script>
|
||||
<script src="{% static 'js/custom.init.js' %}"></script>
|
||||
|
||||
<script>
|
||||
var stack = {dir1: "right", dir2: "up", "push": "top"};
|
||||
{% for message in messages %}
|
||||
$(function() {
|
||||
var notice = new PNotify({
|
||||
text: '{{ message | escapejs }}',
|
||||
title: 'Notification',
|
||||
type: '{{ message | pnotify_type }}',
|
||||
hide: false,
|
||||
addclass: 'stack-bottomright',
|
||||
stack: stack,
|
||||
nonblock: {
|
||||
nonblock: true,
|
||||
nonblock_opacity: .2,
|
||||
},
|
||||
buttons: {
|
||||
closer: false,
|
||||
sticker: false,
|
||||
}
|
||||
});
|
||||
|
||||
notice.get().click(function() {
|
||||
notice.remove();
|
||||
});
|
||||
});
|
||||
{% endfor %}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
65
cabinet/templates/cabinet/_includes/header.html
Normal file
65
cabinet/templates/cabinet/_includes/header.html
Normal file
@@ -0,0 +1,65 @@
|
||||
{% load staticfiles %}
|
||||
|
||||
<header class="header">
|
||||
<div class="logo-container">
|
||||
<a href="{% url 'cabinet:index' %}" class="logo">
|
||||
<img src="{% static 'img/logo-light.png' %}" height="35" alt="Porto Admin"/>
|
||||
</a>
|
||||
<div class="d-md-none toggle-sidebar-left" data-toggle-class="sidebar-left-opened" data-target="html" data-fire-event="sidebar-left-opened">
|
||||
<i class="fas fa-bars" aria-label="Toggle sidebar"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="header-right">
|
||||
<ul class="notifications">
|
||||
<li>
|
||||
<a href="#" class="dropdown-toggle notification-icon" data-toggle="dropdown">
|
||||
<i class="fas fa-bell"></i>
|
||||
<span class="badge">0</span>
|
||||
</a>
|
||||
<div class="dropdown-menu notification-menu">
|
||||
<div class="notification-title">
|
||||
<span class="float-right badge badge-default">0</span>
|
||||
Alerts
|
||||
</div>
|
||||
<div class="content">
|
||||
<ul>
|
||||
<li>
|
||||
No notifications
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<span class="separator"></span>
|
||||
<div id="userbox" class="userbox">
|
||||
<a href="#" data-toggle="dropdown">
|
||||
<figure class="profile-picture">
|
||||
<img src="{% static 'img/!logged-user.jpg' %}" alt="{{ request.user.username }}" class="img-circle"
|
||||
data-lock-picture="{% static 'octopus/images/!logged-user.jpg' %}"/>
|
||||
</figure>
|
||||
<div class="profile-info" data-lock-name="{{ request.user.username }}"{# data-lock-email="johndoe@okler.com" #}>
|
||||
<span class="name">{{ request.user.username }}</span>
|
||||
<span class="role">{% if request.user.is_superuser %}administrator{% else %}user{% endif %}</span>
|
||||
</div>
|
||||
<i class="fa custom-caret"></i>
|
||||
</a>
|
||||
<div class="dropdown-menu">
|
||||
<ul class="list-unstyled mb-2">
|
||||
<li class="divider"></li>
|
||||
<li>
|
||||
<a role="menuitem" tabindex="-1" href="#">
|
||||
<i class="fas fa-user"></i> My Profile
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="menuitem" tabindex="-1" href="{% url 'cabinet:logout' %}">
|
||||
<i class="fas fa-power-off"></i> Logout
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
34
cabinet/templates/cabinet/_includes/sidebar.html
Normal file
34
cabinet/templates/cabinet/_includes/sidebar.html
Normal file
@@ -0,0 +1,34 @@
|
||||
<aside id="sidebar-left" class="sidebar-left">
|
||||
<div class="sidebar-header">
|
||||
<div class="sidebar-title">Modules</div>
|
||||
<div class="sidebar-toggle d-none d-md-block" data-toggle-class="sidebar-left-collapsed" data-target="html" data-fire-event="sidebar-left-toggle">
|
||||
<i class="fas fa-bars" aria-label="Toggle sidebar"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nano">
|
||||
<div class="nano-content">
|
||||
<nav id="menu" class="nav-main" role="navigation">
|
||||
<ul class="nav nav-main">
|
||||
<li class="{% if sidebar_section == 'feeds' %}nav-active{% endif %}">
|
||||
<a href="{% url 'cabinet:feeds:index' %}">
|
||||
<i class="fas fa-rss-square" aria-hidden="true"></i>
|
||||
<span>Feeds</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Maintain Scroll Position
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
if (localStorage.getItem('sidebar-left-position') !== null) {
|
||||
var initialPosition = localStorage.getItem('sidebar-left-position'),
|
||||
sidebarLeft = document.querySelector('#sidebar-left .nano-content');
|
||||
|
||||
sidebarLeft.scrollTop = initialPosition;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
</aside>
|
23
cabinet/templates/cabinet/_internal_base.html
Normal file
23
cabinet/templates/cabinet/_internal_base.html
Normal file
@@ -0,0 +1,23 @@
|
||||
{% extends 'cabinet/_base.html' %}
|
||||
|
||||
{% block page %}
|
||||
<section class="body">
|
||||
{% include 'cabinet/_includes/header.html' %}
|
||||
<div class="inner-wrapper">
|
||||
{% include 'cabinet/_includes/sidebar.html' %}
|
||||
<section role="main" class="content-body">
|
||||
<header class="page-header">
|
||||
<h2>{{ title }}</h2>
|
||||
<div class="right-wrapper text-right">
|
||||
<ol class="breadcrumbs">
|
||||
<li><a href="{% url 'cabinet:index' %}"><i class="fas fa-home"></i></a>
|
||||
{% block breadcrumbs %}{% endblock %}
|
||||
</ol>
|
||||
{# <a class="sidebar-right-toggle" data-open="sidebar-right"><i class="fa fa-chevron-left"></i></a>#}
|
||||
</div>
|
||||
</header>
|
||||
{% block content %}{% endblock %}
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
7
cabinet/templates/cabinet/index.html
Normal file
7
cabinet/templates/cabinet/index.html
Normal file
@@ -0,0 +1,7 @@
|
||||
{% extends 'cabinet/_internal_base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="alert alert-default">
|
||||
Nothing here (yet)! Please select section from sidebar.
|
||||
</div>
|
||||
{% endblock %}
|
69
cabinet/templates/cabinet/login.html
Normal file
69
cabinet/templates/cabinet/login.html
Normal file
@@ -0,0 +1,69 @@
|
||||
{% extends 'cabinet/_base.html' %}
|
||||
{% load staticfiles bootstrap4 %}
|
||||
|
||||
{% block page %}
|
||||
<section class="body-sign">
|
||||
<div class="center-sign">
|
||||
<a href="https://preview.oklerthemes.com/" class="logo float-left">
|
||||
<img src="{% static 'img/logo-light.png' %}" height="54" alt="Porto Admin" />
|
||||
</a>
|
||||
|
||||
<div class="panel card-sign">
|
||||
<div class="card-title-sign mt-3 text-right">
|
||||
<h2 class="title text-uppercase font-weight-bold m-0"><i class="fas fa-user mr-1"></i> Sign In</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
{% bootstrap_form_errors form %}
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<label>Username</label>
|
||||
<div class="input-group">
|
||||
<input name="username" type="text" class="form-control form-control-lg" />
|
||||
<span class="input-group-append">
|
||||
<span class="input-group-text">
|
||||
<i class="fas fa-user"></i>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<div class="clearfix">
|
||||
<label class="float-left">Password</label>
|
||||
{# <a href="pages-recover-password.html" class="float-right">Lost Password?</a>#}
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input name="password" type="password" class="form-control form-control-lg" />
|
||||
<span class="input-group-append">
|
||||
<span class="input-group-text">
|
||||
<i class="fas fa-lock"></i>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-8">
|
||||
<div class="checkbox-custom checkbox-default">
|
||||
<input id="RememberMe" name="rememberme" type="checkbox"/>
|
||||
<label for="RememberMe">Remember Me</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4 text-right">
|
||||
<button type="submit" class="btn btn-primary mt-2">Sign In</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# <p class="text-center">Don't have an account yet? <a href="pages-signup.html">Sign Up!</a></p>#}
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# <p class="text-center text-muted mt-3 mb-3">© Copyright 2017. All Rights Reserved.</p>#}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
0
cabinet/templatetags/__init__.py
Normal file
0
cabinet/templatetags/__init__.py
Normal file
27
cabinet/templatetags/cabinet.py
Normal file
27
cabinet/templatetags/cabinet.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from django import template
|
||||
from django.contrib.messages import constants as message_constants
|
||||
|
||||
|
||||
MESSAGE_LEVEL_TYPES = {
|
||||
message_constants.DEBUG: "info",
|
||||
message_constants.INFO: "info",
|
||||
message_constants.SUCCESS: "success",
|
||||
message_constants.WARNING: "notice",
|
||||
message_constants.ERROR: "error",
|
||||
}
|
||||
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.filter
|
||||
def pnotify_type(message):
|
||||
try:
|
||||
level = message.level
|
||||
except AttributeError:
|
||||
return 'info'
|
||||
else:
|
||||
try:
|
||||
return MESSAGE_LEVEL_TYPES[level]
|
||||
except KeyError:
|
||||
return "info"
|
3
cabinet/tests.py
Normal file
3
cabinet/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
12
cabinet/urls.py
Normal file
12
cabinet/urls.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from django.contrib.auth.views import LogoutView
|
||||
from django.urls import path, include
|
||||
|
||||
from cabinet.views import CabinetIndexView, LoginView
|
||||
|
||||
app_name = 'cabinet'
|
||||
urlpatterns = [
|
||||
path('', CabinetIndexView.as_view(), name='index'),
|
||||
path('login/', LoginView.as_view(), name='login'),
|
||||
path('logout/', LogoutView.as_view(), name='logout'),
|
||||
path('feeds/', include('feeds.urls', namespace='feeds')),
|
||||
]
|
15
cabinet/utils.py
Normal file
15
cabinet/utils.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
|
||||
|
||||
class CabinetViewMixin(LoginRequiredMixin):
|
||||
title = 'No title'
|
||||
sidebar_section = None
|
||||
|
||||
def get_title(self):
|
||||
return self.title
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super(CabinetViewMixin, self).get_context_data(**kwargs)
|
||||
ctx['title'] = self.get_title()
|
||||
ctx['sidebar_section'] = self.sidebar_section
|
||||
return ctx
|
25
cabinet/views.py
Normal file
25
cabinet/views.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from django.contrib.auth.views import LoginView as BaseLoginView
|
||||
from django.views.generic import TemplateView
|
||||
|
||||
from cabinet.utils import CabinetViewMixin
|
||||
|
||||
|
||||
class CabinetIndexView(CabinetViewMixin, TemplateView):
|
||||
template_name = 'cabinet/index.html'
|
||||
title = 'Cabinet home'
|
||||
|
||||
|
||||
class LoginView(BaseLoginView):
|
||||
template_name = 'cabinet/login.html'
|
||||
redirect_authenticated_user = True
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super(LoginView, self).get_context_data(**kwargs)
|
||||
ctx['title'] = 'Login'
|
||||
return ctx
|
||||
|
||||
def form_valid(self, form):
|
||||
res = super(LoginView, self).form_valid(form)
|
||||
if not self.request.POST.get('remember'):
|
||||
self.request.session.set_expiry(0)
|
||||
return res
|
Reference in New Issue
Block a user