mirror of
				https://github.com/Alexander-D-Karpov/akarpov
				synced 2025-11-04 03:27:24 +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):
 | 
			
		||||
    TYPE = "Provider"
 | 
			
		||||
    parent = None
 | 
			
		||||
    children: list[BaseBlock]
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        abstract = True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class BaseStorage(PolymorphicModel):
 | 
			
		||||
    id: uuid.uuid4 = models.UUIDField(
 | 
			
		||||
    id: uuid.UUID = models.UUIDField(
 | 
			
		||||
        primary_key=True, default=uuid.uuid4, editable=False
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,11 @@
 | 
			
		|||
from django.db import models
 | 
			
		||||
 | 
			
		||||
from akarpov.pipeliner.models import BaseBlock
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Workspace(models.Model):
 | 
			
		||||
    blocks: list[BaseBlock]
 | 
			
		||||
 | 
			
		||||
    name = models.CharField(max_length=50, blank=True)
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.profile {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    right: 0;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.profile-wrapper {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.profile-card {
 | 
			
		||||
  background: #E0E0E0;
 | 
			
		||||
  width: 56px;
 | 
			
		||||
| 
						 | 
				
			
			@ -115,10 +129,9 @@ p {
 | 
			
		|||
  width: 218px;
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  float: right;
 | 
			
		||||
  margin: 0px;
 | 
			
		||||
  padding: 15px 20px;
 | 
			
		||||
  background: #FFFFFF;
 | 
			
		||||
  margin-top: 50px;
 | 
			
		||||
  margin: 50px 0 0;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  opacity: 0;
 | 
			
		||||
  -webkit-box-sizing: border-box;
 | 
			
		||||
| 
						 | 
				
			
			@ -492,3 +505,29 @@ p {
 | 
			
		|||
  font-weight: bolder;
 | 
			
		||||
  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 %}
 | 
			
		||||
 | 
			
		||||
{% 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' %}">
 | 
			
		||||
  {% csrf_token %}
 | 
			
		||||
  {{ form|crispy }}
 | 
			
		||||
  {% if redirect_field_value %}
 | 
			
		||||
  <input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
 | 
			
		||||
  {% 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>
 | 
			
		||||
  <button class="primaryAction btn btn-primary" type="submit">{% translate "Sign In" %}</button>
 | 
			
		||||
</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 %}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,6 @@
 | 
			
		|||
 | 
			
		||||
    <link rel="icon" href="{% static 'images/favicons/favicon.ico' %}">
 | 
			
		||||
 | 
			
		||||
    {% block css %}
 | 
			
		||||
    <!-- Latest compiled and minified Bootstrap CSS -->
 | 
			
		||||
    <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">
 | 
			
		||||
| 
						 | 
				
			
			@ -20,6 +19,7 @@
 | 
			
		|||
 | 
			
		||||
    <!-- This file stores project-specific CSS -->
 | 
			
		||||
    <link href="{% static 'css/project.css' %}" rel="stylesheet">
 | 
			
		||||
    {% block css %}
 | 
			
		||||
    {% endblock %}
 | 
			
		||||
    <!-- Le javascript
 | 
			
		||||
    ================================================== -->
 | 
			
		||||
| 
						 | 
				
			
			@ -37,56 +37,87 @@
 | 
			
		|||
  </head>
 | 
			
		||||
 | 
			
		||||
  <body>
 | 
			
		||||
      <div class="container-fluid">
 | 
			
		||||
        <div class="row vh-100 overflow-auto">
 | 
			
		||||
            <div class="sidebar col-12 col-sm-3 col-xl-1 px-sm-2 px-0 bg-dark d-flex sticky-top">
 | 
			
		||||
                <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 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>
 | 
			
		||||
                    </a>
 | 
			
		||||
                    <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_superuser %}
 | 
			
		||||
                        <li>
 | 
			
		||||
                            <a href="/admin/" class="text-muted nav-link px-sm-0 px-2">
 | 
			
		||||
                                <i class="fs-5 bi-speedometer2"></i><span class="ms-1 d-none d-sm-inline">Admin</span> </a>
 | 
			
		||||
                        </li>
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
                        <li>
 | 
			
		||||
                            <a href="#" class="text-muted nav-link px-sm-0 px-2">
 | 
			
		||||
                                <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>
 | 
			
		||||
                    </ul>
 | 
			
		||||
 | 
			
		||||
    <div class="mb-1">
 | 
			
		||||
      <nav class="navbar navbar-expand-md navbar-light bg-light">
 | 
			
		||||
        <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">
 | 
			
		||||
            <span class="navbar-toggler-icon"></span>
 | 
			
		||||
          </button>
 | 
			
		||||
          <a class="navbar-brand" href="{% url 'blog:post_list' %}">akarpov</a>
 | 
			
		||||
                    <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>
 | 
			
		||||
            <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 %}
 | 
			
		||||
                            {% for message in messages %}
 | 
			
		||||
                              <div class="alert alert-dismissible {% if message.tags %}alert-{{ message.tags }}{% endif %}">
 | 
			
		||||
                                {{ message }}
 | 
			
		||||
                                <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
 | 
			
		||||
                              </div>
 | 
			
		||||
                            {% endfor %}
 | 
			
		||||
                          {% endif %}
 | 
			
		||||
 | 
			
		||||
          <div class="collapse navbar-collapse" id="navbarSupportedContent">
 | 
			
		||||
            <ul class="navbar-nav mr-auto">
 | 
			
		||||
              {% if request.user.is_authenticated %}
 | 
			
		||||
                <li class="nav-item">
 | 
			
		||||
                  {# URL provided by django-allauth/account/urls.py #}
 | 
			
		||||
                  <a class="nav-link {% active_link 'users:detail' %}" href="{% url 'users:detail' request.user.username  %}">{% translate "My Profile" %}</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>
 | 
			
		||||
              {% endif %}
 | 
			
		||||
                <li class="nav-item">
 | 
			
		||||
                  {# URL provided by django-allauth/account/urls.py #}
 | 
			
		||||
                  <a id="log-in-link" class="nav-link {% active_link 'account_login' %}" href="{% url 'account_login' %}">{% translate "Sign In" %}</a>
 | 
			
		||||
                </li>
 | 
			
		||||
              {% endif %}
 | 
			
		||||
            </ul>
 | 
			
		||||
          </div>
 | 
			
		||||
                          {% block content %}
 | 
			
		||||
                          {% endblock content %}
 | 
			
		||||
                    </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>
 | 
			
		||||
      </nav>
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="container">
 | 
			
		||||
      {% if messages %}
 | 
			
		||||
        {% for message in messages %}
 | 
			
		||||
          <div class="alert alert-dismissible {% if message.tags %}alert-{{ message.tags }}{% endif %}">
 | 
			
		||||
            {{ message }}
 | 
			
		||||
            <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
 | 
			
		||||
          </div>
 | 
			
		||||
        {% endfor %}
 | 
			
		||||
      {% endif %}
 | 
			
		||||
 | 
			
		||||
      {% block content %}
 | 
			
		||||
      {% endblock content %}
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    {% block modal %}{% endblock modal %}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,8 +9,8 @@
 | 
			
		|||
  {% endif %}
 | 
			
		||||
  <div class="row mb-2">
 | 
			
		||||
  {% for post in post_list %}
 | 
			
		||||
      <div class="col-md-6">
 | 
			
		||||
        <div class="row g-0 border rounded overflow-hidden flex-md-row mb-4 shadow-sm h-md-250 position-relative">
 | 
			
		||||
      <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 blog-cards">
 | 
			
		||||
          <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>
 | 
			
		||||
            <h3 class="mb-0">{{ post.title }}</h3>
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +22,7 @@
 | 
			
		|||
              <i class="bi bi-chat ms-3"></i> {{ post.comment_count }}</p>
 | 
			
		||||
          </div>
 | 
			
		||||
          {% 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 %}
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,54 +4,58 @@
 | 
			
		|||
{% block title %}User: {{ object.username }}{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
<aside class="profile-card">
 | 
			
		||||
  <header>
 | 
			
		||||
    <!-- here’s the avatar -->
 | 
			
		||||
    <a target="_blank" href="#">
 | 
			
		||||
      {% if object.image_cropped %}<img style="object-fit: cover; width: 125px; height: 125px" src="{{ object.image_cropped.url }}" class="hoverZoomLink">{% endif %}
 | 
			
		||||
    </a>
 | 
			
		||||
  <div class="profile-wrapper">
 | 
			
		||||
    <div class="profile">
 | 
			
		||||
      <aside class="profile-card">
 | 
			
		||||
        <header>
 | 
			
		||||
          <!-- here’s the avatar -->
 | 
			
		||||
          <a target="_blank" href="#">
 | 
			
		||||
            {% if object.image_cropped %}<img style="object-fit: cover; width: 125px; height: 125px" src="{{ object.image_cropped.url }}" class="hoverZoomLink">{% endif %}
 | 
			
		||||
          </a>
 | 
			
		||||
 | 
			
		||||
    <!-- the username -->
 | 
			
		||||
    <h1>{{ object.username }}</h1>
 | 
			
		||||
          <!-- the username -->
 | 
			
		||||
          <h1>{{ object.username }}</h1>
 | 
			
		||||
 | 
			
		||||
    <!-- and role or location -->
 | 
			
		||||
    <h2>{% if object.name %}{{ object.name }}{% endif %}</h2>
 | 
			
		||||
          <!-- and role or location -->
 | 
			
		||||
          <h2>{% if object.name %}{{ object.name }}{% endif %}</h2>
 | 
			
		||||
 | 
			
		||||
  </header>
 | 
			
		||||
        </header>
 | 
			
		||||
 | 
			
		||||
  <!-- bit of a bio; who are you? -->
 | 
			
		||||
  <div class="profile-bio">
 | 
			
		||||
        <!-- bit of a bio; who are you? -->
 | 
			
		||||
        <div class="profile-bio">
 | 
			
		||||
 | 
			
		||||
    <p>
 | 
			
		||||
      {{ object.about }}
 | 
			
		||||
    </p>
 | 
			
		||||
          <p>
 | 
			
		||||
            {{ object.about }}
 | 
			
		||||
          </p>
 | 
			
		||||
 | 
			
		||||
        </div>
 | 
			
		||||
       <ul class="profile-social-links">
 | 
			
		||||
        {% if object == request.user %}
 | 
			
		||||
          <li>
 | 
			
		||||
            <a href="{% url 'users:update' %}">
 | 
			
		||||
              <i class="bi bi-sliders"></i>
 | 
			
		||||
            </a>
 | 
			
		||||
          </li>
 | 
			
		||||
          <li>
 | 
			
		||||
            <a href="{% url 'account_email' %}">
 | 
			
		||||
              <i class="bi bi-envelope"></i>
 | 
			
		||||
            </a>
 | 
			
		||||
          </li>
 | 
			
		||||
          <li>
 | 
			
		||||
            <a href="{% url 'account_reset_password' %}">
 | 
			
		||||
              <i class="bi bi-key"></i>
 | 
			
		||||
            </a>
 | 
			
		||||
          </li>
 | 
			
		||||
          <li>
 | 
			
		||||
            <a href="{% url 'socialaccount_connections' %}">
 | 
			
		||||
              <i class="bi bi-person-add"></i>
 | 
			
		||||
            </a>
 | 
			
		||||
          </li>
 | 
			
		||||
 | 
			
		||||
        {% endif %}
 | 
			
		||||
        </ul>
 | 
			
		||||
      <!-- End Action buttons -->
 | 
			
		||||
      </aside>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 <ul class="profile-social-links">
 | 
			
		||||
  {% if object == request.user %}
 | 
			
		||||
    <li>
 | 
			
		||||
      <a href="{% url 'users:update' %}">
 | 
			
		||||
        <i class="bi bi-sliders"></i>
 | 
			
		||||
      </a>
 | 
			
		||||
    </li>
 | 
			
		||||
    <li>
 | 
			
		||||
      <a href="{% url 'account_email' %}">
 | 
			
		||||
        <i class="bi bi-envelope"></i>
 | 
			
		||||
      </a>
 | 
			
		||||
    </li>
 | 
			
		||||
    <li>
 | 
			
		||||
      <a href="{% url 'account_reset_password' %}">
 | 
			
		||||
        <i class="bi bi-key"></i>
 | 
			
		||||
      </a>
 | 
			
		||||
    </li>
 | 
			
		||||
    <li>
 | 
			
		||||
      <a href="{% url 'socialaccount_connections' %}">
 | 
			
		||||
        <i class="bi bi-person-add"></i>
 | 
			
		||||
      </a>
 | 
			
		||||
    </li>
 | 
			
		||||
 | 
			
		||||
  {% endif %}
 | 
			
		||||
  </ul>
 | 
			
		||||
<!-- End Action buttons -->
 | 
			
		||||
</aside>
 | 
			
		||||
{% endblock content %}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
from django.contrib import admin
 | 
			
		||||
 | 
			
		||||
from akarpov.shortener.models import Link
 | 
			
		||||
from akarpov.tools.shortener.models import Link
 | 
			
		||||
 | 
			
		||||
admin.site.register(Link)
 | 
			
		||||
| 
						 | 
				
			
			@ -3,7 +3,7 @@
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
class ShortenerConfig(AppConfig):
 | 
			
		||||
    name = "akarpov.shortener"
 | 
			
		||||
    name = "akarpov.tools.shortener"
 | 
			
		||||
    verbose_name = _("Link shortener")
 | 
			
		||||
 | 
			
		||||
    def ready(self):
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
from django import forms
 | 
			
		||||
from django.core.validators import URLValidator
 | 
			
		||||
 | 
			
		||||
from akarpov.shortener.models import Link
 | 
			
		||||
from akarpov.tools.shortener.models import Link
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LinkForm(forms.ModelForm):
 | 
			
		||||
| 
						 | 
				
			
			@ -15,7 +15,7 @@ class Link(TimeStampedModel):
 | 
			
		|||
    viewed = models.IntegerField(default=0)
 | 
			
		||||
 | 
			
		||||
    def get_absolute_url(self):
 | 
			
		||||
        return reverse("shortener:view", kwargs={"slug": self.slug})
 | 
			
		||||
        return reverse("short_url", kwargs={"slug": self.slug})
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        return f"link to {self.source}"
 | 
			
		||||
| 
						 | 
				
			
			@ -1,21 +1,21 @@
 | 
			
		|||
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
 | 
			
		||||
 | 
			
		||||
lenght = settings.SHORTENER_SLUG_LENGTH
 | 
			
		||||
length = settings.SHORTENER_SLUG_LENGTH
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def generate_slug(pk: int) -> str:
 | 
			
		||||
    if settings.SHORTENER_ADD_SLUG:
 | 
			
		||||
        slug = generate_charset(lenght)
 | 
			
		||||
        slug = generate_charset(length)
 | 
			
		||||
        return slug + get_str_uuid(pk)
 | 
			
		||||
    return get_str_uuid(pk)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_link_from_slug(slug: str, check_whole=False) -> Link | bool:
 | 
			
		||||
    if settings.SHORTENER_ADD_SLUG and not check_whole:
 | 
			
		||||
        payload = slug[lenght:]
 | 
			
		||||
        payload = slug[length:]
 | 
			
		||||
        pk = get_pk_from_uuid(payload)
 | 
			
		||||
        try:
 | 
			
		||||
            return Link.objects.get(pk=pk)
 | 
			
		||||
| 
						 | 
				
			
			@ -1,8 +1,8 @@
 | 
			
		|||
from django.db.models.signals import post_save
 | 
			
		||||
from django.dispatch import receiver
 | 
			
		||||
 | 
			
		||||
from akarpov.shortener.models import Link
 | 
			
		||||
from akarpov.shortener.services import generate_slug
 | 
			
		||||
from akarpov.tools.shortener.models import Link
 | 
			
		||||
from akarpov.tools.shortener.services import generate_slug
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@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.views.generic import CreateView, DetailView
 | 
			
		||||
 | 
			
		||||
from akarpov.shortener.forms import LinkForm
 | 
			
		||||
from akarpov.shortener.models import Link
 | 
			
		||||
from akarpov.shortener.services import get_link_from_slug
 | 
			
		||||
from akarpov.tools.shortener.forms import LinkForm
 | 
			
		||||
from akarpov.tools.shortener.models import Link
 | 
			
		||||
from akarpov.tools.shortener.services import get_link_from_slug
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ShortLinkCreateView(CreateView):
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,7 @@
 | 
			
		|||
from django.urls import include, path
 | 
			
		||||
 | 
			
		||||
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.blog",
 | 
			
		||||
    "akarpov.files",
 | 
			
		||||
    "akarpov.shortener",
 | 
			
		||||
    "akarpov.pipeliner",
 | 
			
		||||
    "akarpov.tools.shortener",
 | 
			
		||||
    "akarpov.tools.qr",
 | 
			
		||||
]
 | 
			
		||||
# https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
 | 
			
		||||
| 
						 | 
				
			
			@ -519,4 +519,4 @@
 | 
			
		|||
 | 
			
		||||
# ACTIVE_LINK
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
ACTIVE_LINK_CSS_CLASS = "active"
 | 
			
		||||
ACTIVE_LINK_CSS_CLASS = "nav-active"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,8 @@
 | 
			
		|||
    SpectacularSwaggerView,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
from akarpov.tools.shortener.views import link_detail_view
 | 
			
		||||
 | 
			
		||||
urlpatterns = [
 | 
			
		||||
    path("home", TemplateView.as_view(template_name="pages/home.html"), name="home"),
 | 
			
		||||
    path(
 | 
			
		||||
| 
						 | 
				
			
			@ -22,10 +24,10 @@
 | 
			
		|||
    # User management
 | 
			
		||||
    path("users/", include("akarpov.users.urls", namespace="users")),
 | 
			
		||||
    path("tools/", include("akarpov.tools.urls", namespace="tools")),
 | 
			
		||||
    path("shortener/", include("akarpov.shortener.urls", namespace="shortener")),
 | 
			
		||||
    path("ckeditor/", include("ckeditor_uploader.urls")),
 | 
			
		||||
    path("accounts/", include("allauth.urls")),
 | 
			
		||||
    path("", include("akarpov.blog.urls", namespace="blog")),
 | 
			
		||||
    path("s/<str:slug>", link_detail_view, name="short_url"),
 | 
			
		||||
    # Your stuff: custom urls includes go here
 | 
			
		||||
] + 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]]
 | 
			
		||||
name = "django-stubs"
 | 
			
		||||
version = "1.13.1"
 | 
			
		||||
version = "1.14.0"
 | 
			
		||||
description = "Mypy stubs for Django"
 | 
			
		||||
category = "main"
 | 
			
		||||
optional = false
 | 
			
		||||
python-versions = ">=3.7"
 | 
			
		||||
files = [
 | 
			
		||||
    {file = "django-stubs-1.13.1.tar.gz", hash = "sha256:bcc618ba353dabc540d982b9dac1d5a1921652f8fc2a13653d545a57d5e3cc0f"},
 | 
			
		||||
    {file = "django_stubs-1.13.1-py3-none-any.whl", hash = "sha256:fbf2ee6a4bce76c3eb5f6707ccadb4cf1c2f1ec485e8c44701ca8de2d0a5df18"},
 | 
			
		||||
    {file = "django-stubs-1.14.0.tar.gz", hash = "sha256:d53bcd4975a54ca5c9abbbd33b61f40d44191971018f2ea54f73b0a6a99e1a8b"},
 | 
			
		||||
    {file = "django_stubs-1.14.0-py3-none-any.whl", hash = "sha256:b081d64d923171f79d4e57899b0980da847e4046b91166e3658a6151645a36c5"},
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[package.dependencies]
 | 
			
		||||
django = "*"
 | 
			
		||||
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 = "*"
 | 
			
		||||
types-pytz = "*"
 | 
			
		||||
types-PyYAML = "*"
 | 
			
		||||
typing-extensions = "*"
 | 
			
		||||
 | 
			
		||||
[package.extras]
 | 
			
		||||
compatible-mypy = ["mypy (>=0.980,<0.990)"]
 | 
			
		||||
compatible-mypy = ["mypy (>=0.991,<1.0)"]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "django-stubs-ext"
 | 
			
		||||
| 
						 | 
				
			
			@ -2046,7 +2049,6 @@ category = "main"
 | 
			
		|||
optional = false
 | 
			
		||||
python-versions = "*"
 | 
			
		||||
files = [
 | 
			
		||||
    {file = "livereload-2.6.3-py2.py3-none-any.whl", hash = "sha256:ad4ac6f53b2d62bb6ce1a5e6e96f1f00976a32348afedcb4b6d68df2a1d346e4"},
 | 
			
		||||
    {file = "livereload-2.6.3.tar.gz", hash = "sha256:776f2f865e59fde56490a56bcc6773b6917366bce0c267c60ee8aaf1a0959869"},
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3663,6 +3665,7 @@ category = "main"
 | 
			
		|||
optional = false
 | 
			
		||||
python-versions = "*"
 | 
			
		||||
files = [
 | 
			
		||||
    {file = "wcwidth-0.2.6-py2.py3-none-any.whl", hash = "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e"},
 | 
			
		||||
    {file = "wcwidth-0.2.6.tar.gz", hash = "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"},
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3777,4 +3780,4 @@ files = [
 | 
			
		|||
[metadata]
 | 
			
		||||
lock-version = "2.0"
 | 
			
		||||
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"
 | 
			
		||||
watchfiles = "^0.18.1"
 | 
			
		||||
mypy = "^0.991"
 | 
			
		||||
django-stubs = "^1.13.1"
 | 
			
		||||
django-stubs = {extras = ["compatible-mypy"], version = "^1.14.0"}
 | 
			
		||||
pytest = "^7.2.0"
 | 
			
		||||
pytest-sugar = "^0.9.6"
 | 
			
		||||
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]
 | 
			
		||||
django_settings_module = config.settings.test
 | 
			
		||||
# https://github.com/typeddjango/django-stubs/issues/1158
 | 
			
		||||
django-manager-missing = False
 | 
			
		||||
 | 
			
		||||
[mypy-*.migrations.*]
 | 
			
		||||
# Django migrations should not produce any errors:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user