mirror of
https://github.com/Alexander-D-Karpov/akarpov
synced 2024-11-22 02:46:33 +03:00
updated navbar, reformed project structure
This commit is contained in:
parent
727f6a6f9e
commit
095a0d02f8
|
@ -38,13 +38,14 @@ def __str__(self):
|
||||||
class ProviderBlock(BaseBlock):
|
class ProviderBlock(BaseBlock):
|
||||||
TYPE = "Provider"
|
TYPE = "Provider"
|
||||||
parent = None
|
parent = None
|
||||||
|
children: list[BaseBlock]
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
|
|
||||||
class BaseStorage(PolymorphicModel):
|
class BaseStorage(PolymorphicModel):
|
||||||
id: uuid.uuid4 = models.UUIDField(
|
id: uuid.UUID = models.UUIDField(
|
||||||
primary_key=True, default=uuid.uuid4, editable=False
|
primary_key=True, default=uuid.uuid4, editable=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
|
from akarpov.pipeliner.models import BaseBlock
|
||||||
|
|
||||||
|
|
||||||
class Workspace(models.Model):
|
class Workspace(models.Model):
|
||||||
|
blocks: list[BaseBlock]
|
||||||
|
|
||||||
name = models.CharField(max_length=50, blank=True)
|
name = models.CharField(max_length=50, blank=True)
|
||||||
slug = models.SlugField(max_length=8)
|
slug = models.SlugField(max_length=8)
|
||||||
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
from django.urls import path
|
|
||||||
|
|
||||||
from akarpov.shortener.views import link_detail_view, short_link_create_view
|
|
||||||
|
|
||||||
app_name = "shortener"
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path("", short_link_create_view, name="create"),
|
|
||||||
path("<str:slug>", link_detail_view, name="view"),
|
|
||||||
]
|
|
|
@ -31,6 +31,20 @@ p {
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.profile {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-wrapper {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
.profile-card {
|
.profile-card {
|
||||||
background: #E0E0E0;
|
background: #E0E0E0;
|
||||||
width: 56px;
|
width: 56px;
|
||||||
|
@ -115,10 +129,9 @@ p {
|
||||||
width: 218px;
|
width: 218px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
float: right;
|
float: right;
|
||||||
margin: 0px;
|
|
||||||
padding: 15px 20px;
|
padding: 15px 20px;
|
||||||
background: #FFFFFF;
|
background: #FFFFFF;
|
||||||
margin-top: 50px;
|
margin: 50px 0 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
-webkit-box-sizing: border-box;
|
-webkit-box-sizing: border-box;
|
||||||
|
@ -492,3 +505,29 @@ p {
|
||||||
font-weight: bolder;
|
font-weight: bolder;
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
max-height: 15%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 576px) {
|
||||||
|
.h-sm-100 {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.sidebar {
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog-card {
|
||||||
|
margin-bottom: -99999px;
|
||||||
|
padding: 10px 10px 99999px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-active::before {
|
||||||
|
content: '→';
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-active {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
|
@ -12,48 +12,25 @@
|
||||||
|
|
||||||
{% get_providers as socialaccount_providers %}
|
{% get_providers as socialaccount_providers %}
|
||||||
|
|
||||||
{% if socialaccount_providers %}
|
|
||||||
<p>
|
|
||||||
{% translate "Please sign in with one of your existing third party accounts:" %}
|
|
||||||
{% if ACCOUNT_ALLOW_REGISTRATION %}
|
|
||||||
{% blocktranslate trimmed %}
|
|
||||||
Or, <a href="{{ signup_url }}">sign up</a>
|
|
||||||
for a {{ site_name }} account and sign in below:
|
|
||||||
{% endblocktranslate %}
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="socialaccount_ballot">
|
|
||||||
|
|
||||||
<ul class="socialaccount_providers">
|
|
||||||
{% include "socialaccount/snippets/provider_list.html" with process="login" %}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div class="login-or">{% translate "or" %}</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% include "socialaccount/snippets/login_extra.html" %}
|
|
||||||
|
|
||||||
{% else %}
|
|
||||||
{% if ACCOUNT_ALLOW_REGISTRATION %}
|
|
||||||
<p>
|
|
||||||
{% blocktranslate trimmed %}
|
|
||||||
If you have not created an account yet, then please
|
|
||||||
<a href="{{ signup_url }}">sign up</a> first.
|
|
||||||
{% endblocktranslate %}
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<form class="login" method="POST" action="{% url 'account_login' %}">
|
<form class="login" method="POST" action="{% url 'account_login' %}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form|crispy }}
|
{{ form|crispy }}
|
||||||
{% if redirect_field_value %}
|
{% if redirect_field_value %}
|
||||||
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
|
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<button class="primaryAction btn btn-primary me-3" type="submit">{% translate "Sign In" %}</button>
|
||||||
<a class="button secondaryAction" href="{% url 'account_reset_password' %}">{% translate "Forgot Password?" %}</a>
|
<a class="button secondaryAction" href="{% url 'account_reset_password' %}">{% translate "Forgot Password?" %}</a>
|
||||||
<button class="primaryAction btn btn-primary" type="submit">{% translate "Sign In" %}</button>
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<p class="mt-2 mb-1">Alternative: </p>
|
||||||
|
|
||||||
|
{% if socialaccount_providers %}
|
||||||
|
<div class="socialaccount_ballot">
|
||||||
|
<ul class="socialaccount_providers">
|
||||||
|
{% include "socialaccount/snippets/provider_list.html" with process="login" %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% include "socialaccount/snippets/login_extra.html" %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
|
|
||||||
<link rel="icon" href="{% static 'images/favicons/favicon.ico' %}">
|
<link rel="icon" href="{% static 'images/favicons/favicon.ico' %}">
|
||||||
|
|
||||||
{% block css %}
|
|
||||||
<!-- Latest compiled and minified Bootstrap CSS -->
|
<!-- Latest compiled and minified Bootstrap CSS -->
|
||||||
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
|
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.2/font/bootstrap-icons.css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.2/font/bootstrap-icons.css">
|
||||||
|
@ -20,6 +19,7 @@
|
||||||
|
|
||||||
<!-- This file stores project-specific CSS -->
|
<!-- This file stores project-specific CSS -->
|
||||||
<link href="{% static 'css/project.css' %}" rel="stylesheet">
|
<link href="{% static 'css/project.css' %}" rel="stylesheet">
|
||||||
|
{% block css %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
<!-- Le javascript
|
<!-- Le javascript
|
||||||
================================================== -->
|
================================================== -->
|
||||||
|
@ -37,45 +37,69 @@
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div class="mb-1">
|
|
||||||
<nav class="navbar navbar-expand-md navbar-light bg-light">
|
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<button class="navbar-toggler navbar-toggler-right" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
<div class="row vh-100 overflow-auto">
|
||||||
<span class="navbar-toggler-icon"></span>
|
<div class="sidebar col-12 col-sm-3 col-xl-1 px-sm-2 px-0 bg-dark d-flex sticky-top">
|
||||||
</button>
|
<div class="d-flex flex-sm-column flex-row flex-grow-1 align-items-center align-items-sm-start px-3 pt-2 text-white">
|
||||||
<a class="navbar-brand" href="{% url 'blog:post_list' %}">akarpov</a>
|
<a href="/" class="d-flex align-items-center pb-sm-3 mb-md-0 me-md-auto text-white text-wrap text-decoration-none">
|
||||||
|
<span class="fs-5">A<span class="d-none d-sm-inline">karpov</span></span>
|
||||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
</a>
|
||||||
<ul class="navbar-nav mr-auto">
|
<ul class="nav nav-pills flex-sm-column flex-row flex-nowrap flex-shrink-1 flex-sm-grow-0 flex-grow-1 mb-sm-auto mb-0 justify-content-center align-items-center align-items-sm-start" id="menu">
|
||||||
{% if request.user.is_authenticated %}
|
{% if request.user.is_superuser %}
|
||||||
<li class="nav-item">
|
<li>
|
||||||
{# URL provided by django-allauth/account/urls.py #}
|
<a href="/admin/" class="text-muted nav-link px-sm-0 px-2">
|
||||||
<a class="nav-link {% active_link 'users:detail' %}" href="{% url 'users:detail' request.user.username %}">{% translate "My Profile" %}</a>
|
<i class="fs-5 bi-speedometer2"></i><span class="ms-1 d-none d-sm-inline">Admin</span> </a>
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
{# URL provided by django-allauth/account/urls.py #}
|
|
||||||
<a class="nav-link {% active_link 'account_logout' %}" href="{% url 'account_logout' %}">{% if request.user.image_cropped %}<img class="rounded" width="20" src="{{ request.user.image_cropped.url }}" alt=""> {% endif %}{% translate "Sign Out" %}</a>
|
|
||||||
</li>
|
|
||||||
{% else %}
|
|
||||||
{% if ACCOUNT_ALLOW_REGISTRATION %}
|
|
||||||
<li class="nav-item">
|
|
||||||
{# URL provided by django-allauth/account/urls.py #}
|
|
||||||
<a id="sign-up-link" class="nav-link {% active_link 'account_signup' %}" href="{% url 'account_signup' %}">{% translate "Sign Up" %}</a>
|
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li class="nav-item">
|
<li>
|
||||||
{# URL provided by django-allauth/account/urls.py #}
|
<a href="#" class="text-muted nav-link px-sm-0 px-2">
|
||||||
<a id="log-in-link" class="nav-link {% active_link 'account_login' %}" href="{% url 'account_login' %}">{% translate "Sign In" %}</a>
|
<i class="fs-5 bi-table"></i><span class="ms-1 d-none d-sm-inline">Orders</span></a>
|
||||||
|
</li>
|
||||||
|
<li class="dropdown">
|
||||||
|
<a href="#" class="text-muted nav-link dropdown-toggle px-sm-0 px-1" id="dropdown" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
<i class="fs-5 bi-terminal-fill"></i><span class="ms-1 d-none d-sm-inline">Apps</span>
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu dropdown-menu-dark text-small shadow" aria-labelledby="dropdown">
|
||||||
|
<li><a class="dropdown-item {% active_link 'tools:qr:create' %}" href="{% url 'tools:qr:create' %}">QR generator</a></li>
|
||||||
|
<li><a class="dropdown-item {% active_link 'tools:shortener:create' %}" href="{% url 'tools:shortener:create' %}">URL shortcuter</a></li>
|
||||||
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
|
<div class="dropdown py-sm-4 mt-sm-auto ms-auto ms-sm-0 flex-shrink-1">
|
||||||
|
{% if request.user.is_authenticated %}
|
||||||
|
<a href="#" class="d-flex align-items-center text-white text-decoration-none dropdown-toggle" id="dropdownUser1" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
{% if request.user.image_cropped %}<img src="{{ request.user.image_cropped.url }}" alt="hugenerd" width="28" height="28" class="rounded-circle">{% endif %}
|
||||||
|
<span class="d-none d-sm-inline mx-1">{{ request.user.username }}</span>
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu dropdown-menu-dark text-small shadow" aria-labelledby="dropdownUser1">
|
||||||
|
<li><a class="dropdown-item {% active_link 'users:update' %}" href="{% url 'users:update' %}">Settings</a></li>
|
||||||
|
<li><a class="dropdown-item {% active_link 'users:detail' request.user.username %}" href="{% url 'users:detail' request.user.username %}">Profile</a></li>
|
||||||
|
<li>
|
||||||
|
<hr class="dropdown-divider">
|
||||||
|
</li>
|
||||||
|
<li><a class="dropdown-item" href="{% url 'account_logout' %}">Sign out</a></li>
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
<ul class="nav nav-pills flex-sm-column flex-row flex-nowrap flex-shrink-1 flex-sm-grow-0 flex-grow-1 py-sm-4 mt-sm-auto ms-auto ms-sm-0" id="menu">
|
||||||
|
{% if ACCOUNT_ALLOW_REGISTRATION %}
|
||||||
|
<li>
|
||||||
|
<a href="{% url 'account_signup' %}" class="text-muted nav-link px-sm-0 px-2 {% active_link 'account_signup' %}">
|
||||||
|
<i class="fs-5 bi-person"></i><span class="ms-1 d-none d-sm-inline">Sign up</span> </a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
<li>
|
||||||
|
<a href="{% url 'account_login' %}" class="nav-link px-sm-0 px-2 {% active_link 'account_login' %} text-muted">
|
||||||
|
<i class="fs-5 bi-box-arrow-in-right"></i><span class="ms-2 d-none d-sm-inline"> Log in</span> </a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="container">
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col d-flex flex-column h-sm-100">
|
||||||
|
<main class="row overflow-aut px-lg-4">
|
||||||
|
<div class="col pt-4">
|
||||||
{% if messages %}
|
{% if messages %}
|
||||||
{% for message in messages %}
|
{% for message in messages %}
|
||||||
<div class="alert alert-dismissible {% if message.tags %}alert-{{ message.tags }}{% endif %}">
|
<div class="alert alert-dismissible {% if message.tags %}alert-{{ message.tags }}{% endif %}">
|
||||||
|
@ -88,6 +112,13 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
</div>
|
</div>
|
||||||
|
</main>
|
||||||
|
<footer class="row bg-light py-1 mt-auto text-center">
|
||||||
|
<div class="col"> Writen by sanspie, find source code <a href="https://github.com/Alexander-D-Karpov/akarpov">here</a> </div>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% block modal %}{% endblock modal %}
|
{% block modal %}{% endblock modal %}
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="row mb-2">
|
<div class="row mb-2">
|
||||||
{% for post in post_list %}
|
{% for post in post_list %}
|
||||||
<div class="col-md-6">
|
<div class="col-md-6 col-xl-12">
|
||||||
<div class="row g-0 border rounded overflow-hidden flex-md-row mb-4 shadow-sm h-md-250 position-relative">
|
<div class="row g-0 border rounded overflow-hidden flex-md-row mb-4 shadow-sm h-md-250 position-relative blog-cards">
|
||||||
<div class="col p-4 d-flex flex-column position-static">
|
<div class="col p-4 d-flex flex-column position-static">
|
||||||
<strong style="color: {{ post.h_tag.color }}" class="d-inline-block mb-2">{{ post.h_tag.name }}</strong>
|
<strong style="color: {{ post.h_tag.color }}" class="d-inline-block mb-2">{{ post.h_tag.name }}</strong>
|
||||||
<h3 class="mb-0">{{ post.title }}</h3>
|
<h3 class="mb-0">{{ post.title }}</h3>
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
<i class="bi bi-chat ms-3"></i> {{ post.comment_count }}</p>
|
<i class="bi bi-chat ms-3"></i> {{ post.comment_count }}</p>
|
||||||
</div>
|
</div>
|
||||||
{% if post.image_cropped %}
|
{% if post.image_cropped %}
|
||||||
<img class="col-auto d-none d-lg-block img-fluid" style="object-fit: cover" src="{{ post.image_cropped.url }}" alt="">
|
<img class="col-auto d-none d-lg-block img-fluid col-xl-3" style="object-fit: cover" src="{{ post.image_cropped.url }}" alt="">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
{% block title %}User: {{ object.username }}{% endblock %}
|
{% block title %}User: {{ object.username }}{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<div class="profile-wrapper">
|
||||||
|
<div class="profile">
|
||||||
<aside class="profile-card">
|
<aside class="profile-card">
|
||||||
<header>
|
<header>
|
||||||
<!-- here’s the avatar -->
|
<!-- here’s the avatar -->
|
||||||
|
@ -54,4 +56,6 @@
|
||||||
</ul>
|
</ul>
|
||||||
<!-- End Action buttons -->
|
<!-- End Action buttons -->
|
||||||
</aside>
|
</aside>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from akarpov.shortener.models import Link
|
from akarpov.tools.shortener.models import Link
|
||||||
|
|
||||||
admin.site.register(Link)
|
admin.site.register(Link)
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
|
|
||||||
class ShortenerConfig(AppConfig):
|
class ShortenerConfig(AppConfig):
|
||||||
name = "akarpov.shortener"
|
name = "akarpov.tools.shortener"
|
||||||
verbose_name = _("Link shortener")
|
verbose_name = _("Link shortener")
|
||||||
|
|
||||||
def ready(self):
|
def ready(self):
|
|
@ -1,7 +1,7 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.core.validators import URLValidator
|
from django.core.validators import URLValidator
|
||||||
|
|
||||||
from akarpov.shortener.models import Link
|
from akarpov.tools.shortener.models import Link
|
||||||
|
|
||||||
|
|
||||||
class LinkForm(forms.ModelForm):
|
class LinkForm(forms.ModelForm):
|
|
@ -15,7 +15,7 @@ class Link(TimeStampedModel):
|
||||||
viewed = models.IntegerField(default=0)
|
viewed = models.IntegerField(default=0)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse("shortener:view", kwargs={"slug": self.slug})
|
return reverse("short_url", kwargs={"slug": self.slug})
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"link to {self.source}"
|
return f"link to {self.source}"
|
|
@ -1,21 +1,21 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from akarpov.shortener.models import Link
|
from akarpov.tools.shortener.models import Link
|
||||||
from akarpov.utils.generators import generate_charset, get_pk_from_uuid, get_str_uuid
|
from akarpov.utils.generators import generate_charset, get_pk_from_uuid, get_str_uuid
|
||||||
|
|
||||||
lenght = settings.SHORTENER_SLUG_LENGTH
|
length = settings.SHORTENER_SLUG_LENGTH
|
||||||
|
|
||||||
|
|
||||||
def generate_slug(pk: int) -> str:
|
def generate_slug(pk: int) -> str:
|
||||||
if settings.SHORTENER_ADD_SLUG:
|
if settings.SHORTENER_ADD_SLUG:
|
||||||
slug = generate_charset(lenght)
|
slug = generate_charset(length)
|
||||||
return slug + get_str_uuid(pk)
|
return slug + get_str_uuid(pk)
|
||||||
return get_str_uuid(pk)
|
return get_str_uuid(pk)
|
||||||
|
|
||||||
|
|
||||||
def get_link_from_slug(slug: str, check_whole=False) -> Link | bool:
|
def get_link_from_slug(slug: str, check_whole=False) -> Link | bool:
|
||||||
if settings.SHORTENER_ADD_SLUG and not check_whole:
|
if settings.SHORTENER_ADD_SLUG and not check_whole:
|
||||||
payload = slug[lenght:]
|
payload = slug[length:]
|
||||||
pk = get_pk_from_uuid(payload)
|
pk = get_pk_from_uuid(payload)
|
||||||
try:
|
try:
|
||||||
return Link.objects.get(pk=pk)
|
return Link.objects.get(pk=pk)
|
|
@ -1,8 +1,8 @@
|
||||||
from django.db.models.signals import post_save
|
from django.db.models.signals import post_save
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|
||||||
from akarpov.shortener.models import Link
|
from akarpov.tools.shortener.models import Link
|
||||||
from akarpov.shortener.services import generate_slug
|
from akarpov.tools.shortener.services import generate_slug
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=Link)
|
@receiver(post_save, sender=Link)
|
9
akarpov/tools/shortener/urls.py
Normal file
9
akarpov/tools/shortener/urls.py
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from akarpov.tools.shortener.views import short_link_create_view
|
||||||
|
|
||||||
|
app_name = "shortener"
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path("", short_link_create_view, name="create"),
|
||||||
|
]
|
|
@ -1,9 +1,9 @@
|
||||||
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
|
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
|
||||||
from django.views.generic import CreateView, DetailView
|
from django.views.generic import CreateView, DetailView
|
||||||
|
|
||||||
from akarpov.shortener.forms import LinkForm
|
from akarpov.tools.shortener.forms import LinkForm
|
||||||
from akarpov.shortener.models import Link
|
from akarpov.tools.shortener.models import Link
|
||||||
from akarpov.shortener.services import get_link_from_slug
|
from akarpov.tools.shortener.services import get_link_from_slug
|
||||||
|
|
||||||
|
|
||||||
class ShortLinkCreateView(CreateView):
|
class ShortLinkCreateView(CreateView):
|
|
@ -1,4 +1,7 @@
|
||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
|
|
||||||
app_name = "tools"
|
app_name = "tools"
|
||||||
urlpatterns = [path("qr/", include("akarpov.tools.qr.urls", namespace="qr"))]
|
urlpatterns = [
|
||||||
|
path("qr/", include("akarpov.tools.qr.urls", namespace="qr")),
|
||||||
|
path("shortener/", include("akarpov.tools.shortener.urls", namespace="shortener")),
|
||||||
|
]
|
||||||
|
|
|
@ -141,8 +141,8 @@
|
||||||
"akarpov.users",
|
"akarpov.users",
|
||||||
"akarpov.blog",
|
"akarpov.blog",
|
||||||
"akarpov.files",
|
"akarpov.files",
|
||||||
"akarpov.shortener",
|
|
||||||
"akarpov.pipeliner",
|
"akarpov.pipeliner",
|
||||||
|
"akarpov.tools.shortener",
|
||||||
"akarpov.tools.qr",
|
"akarpov.tools.qr",
|
||||||
]
|
]
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
|
# https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
|
||||||
|
@ -519,4 +519,4 @@
|
||||||
|
|
||||||
# ACTIVE_LINK
|
# ACTIVE_LINK
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
ACTIVE_LINK_CSS_CLASS = "active"
|
ACTIVE_LINK_CSS_CLASS = "nav-active"
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
SpectacularSwaggerView,
|
SpectacularSwaggerView,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from akarpov.tools.shortener.views import link_detail_view
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("home", TemplateView.as_view(template_name="pages/home.html"), name="home"),
|
path("home", TemplateView.as_view(template_name="pages/home.html"), name="home"),
|
||||||
path(
|
path(
|
||||||
|
@ -22,10 +24,10 @@
|
||||||
# User management
|
# User management
|
||||||
path("users/", include("akarpov.users.urls", namespace="users")),
|
path("users/", include("akarpov.users.urls", namespace="users")),
|
||||||
path("tools/", include("akarpov.tools.urls", namespace="tools")),
|
path("tools/", include("akarpov.tools.urls", namespace="tools")),
|
||||||
path("shortener/", include("akarpov.shortener.urls", namespace="shortener")),
|
|
||||||
path("ckeditor/", include("ckeditor_uploader.urls")),
|
path("ckeditor/", include("ckeditor_uploader.urls")),
|
||||||
path("accounts/", include("allauth.urls")),
|
path("accounts/", include("allauth.urls")),
|
||||||
path("", include("akarpov.blog.urls", namespace="blog")),
|
path("", include("akarpov.blog.urls", namespace="blog")),
|
||||||
|
path("s/<str:slug>", link_detail_view, name="short_url"),
|
||||||
# Your stuff: custom urls includes go here
|
# Your stuff: custom urls includes go here
|
||||||
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
|
||||||
|
|
17
poetry.lock
generated
17
poetry.lock
generated
|
@ -1275,27 +1275,30 @@ celery = ["celery (>=5.1)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "django-stubs"
|
name = "django-stubs"
|
||||||
version = "1.13.1"
|
version = "1.14.0"
|
||||||
description = "Mypy stubs for Django"
|
description = "Mypy stubs for Django"
|
||||||
category = "main"
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
{file = "django-stubs-1.13.1.tar.gz", hash = "sha256:bcc618ba353dabc540d982b9dac1d5a1921652f8fc2a13653d545a57d5e3cc0f"},
|
{file = "django-stubs-1.14.0.tar.gz", hash = "sha256:d53bcd4975a54ca5c9abbbd33b61f40d44191971018f2ea54f73b0a6a99e1a8b"},
|
||||||
{file = "django_stubs-1.13.1-py3-none-any.whl", hash = "sha256:fbf2ee6a4bce76c3eb5f6707ccadb4cf1c2f1ec485e8c44701ca8de2d0a5df18"},
|
{file = "django_stubs-1.14.0-py3-none-any.whl", hash = "sha256:b081d64d923171f79d4e57899b0980da847e4046b91166e3658a6151645a36c5"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
django = "*"
|
django = "*"
|
||||||
django-stubs-ext = ">=0.7.0"
|
django-stubs-ext = ">=0.7.0"
|
||||||
mypy = ">=0.980"
|
mypy = [
|
||||||
|
{version = ">=0.980"},
|
||||||
|
{version = ">=0.991,<1.0", optional = true, markers = "extra == \"compatible-mypy\""},
|
||||||
|
]
|
||||||
tomli = "*"
|
tomli = "*"
|
||||||
types-pytz = "*"
|
types-pytz = "*"
|
||||||
types-PyYAML = "*"
|
types-PyYAML = "*"
|
||||||
typing-extensions = "*"
|
typing-extensions = "*"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
compatible-mypy = ["mypy (>=0.980,<0.990)"]
|
compatible-mypy = ["mypy (>=0.991,<1.0)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "django-stubs-ext"
|
name = "django-stubs-ext"
|
||||||
|
@ -2046,7 +2049,6 @@ category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
files = [
|
files = [
|
||||||
{file = "livereload-2.6.3-py2.py3-none-any.whl", hash = "sha256:ad4ac6f53b2d62bb6ce1a5e6e96f1f00976a32348afedcb4b6d68df2a1d346e4"},
|
|
||||||
{file = "livereload-2.6.3.tar.gz", hash = "sha256:776f2f865e59fde56490a56bcc6773b6917366bce0c267c60ee8aaf1a0959869"},
|
{file = "livereload-2.6.3.tar.gz", hash = "sha256:776f2f865e59fde56490a56bcc6773b6917366bce0c267c60ee8aaf1a0959869"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -3663,6 +3665,7 @@ category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
files = [
|
files = [
|
||||||
|
{file = "wcwidth-0.2.6-py2.py3-none-any.whl", hash = "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e"},
|
||||||
{file = "wcwidth-0.2.6.tar.gz", hash = "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"},
|
{file = "wcwidth-0.2.6.tar.gz", hash = "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -3777,4 +3780,4 @@ files = [
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.11"
|
python-versions = "^3.11"
|
||||||
content-hash = "392fed32dc5e397e6fd56683185d571a8bd93faaf71d54bba6479d1dce4dab84"
|
content-hash = "fe807601a32feb33caa293b0a8639c33ccf436b02efac27a56783dafb95f1942"
|
||||||
|
|
|
@ -37,7 +37,7 @@ werkzeug = {extras = ["watchdog"], version = "^2.2.2"}
|
||||||
ipdb = "^0.13.11"
|
ipdb = "^0.13.11"
|
||||||
watchfiles = "^0.18.1"
|
watchfiles = "^0.18.1"
|
||||||
mypy = "^0.991"
|
mypy = "^0.991"
|
||||||
django-stubs = "^1.13.1"
|
django-stubs = {extras = ["compatible-mypy"], version = "^1.14.0"}
|
||||||
pytest = "^7.2.0"
|
pytest = "^7.2.0"
|
||||||
pytest-sugar = "^0.9.6"
|
pytest-sugar = "^0.9.6"
|
||||||
djangorestframework-stubs = {extras = ["compatible-mypy"], version = "^1.8.0"}
|
djangorestframework-stubs = {extras = ["compatible-mypy"], version = "^1.8.0"}
|
||||||
|
|
|
@ -28,8 +28,6 @@ plugins = mypy_django_plugin.main, mypy_drf_plugin.main
|
||||||
|
|
||||||
[mypy.plugins.django-stubs]
|
[mypy.plugins.django-stubs]
|
||||||
django_settings_module = config.settings.test
|
django_settings_module = config.settings.test
|
||||||
# https://github.com/typeddjango/django-stubs/issues/1158
|
|
||||||
django-manager-missing = False
|
|
||||||
|
|
||||||
[mypy-*.migrations.*]
|
[mypy-*.migrations.*]
|
||||||
# Django migrations should not produce any errors:
|
# Django migrations should not produce any errors:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user