mirror of
https://github.com/Alexander-D-Karpov/akarpov
synced 2024-11-22 07:26:33 +03:00
linter, docker updated, minor byg fixed and shortener updates
This commit is contained in:
parent
222138193b
commit
22db41f6f8
|
@ -21,7 +21,7 @@ repos:
|
|||
- id: black
|
||||
|
||||
- repo: https://github.com/PyCQA/isort
|
||||
rev: 5.10.1
|
||||
rev: 5.12.0
|
||||
hooks:
|
||||
- id: isort
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from akarpov.shortener.models import Link
|
||||
|
||||
admin.site.register(Link)
|
17
akarpov/shortener/forms.py
Normal file
17
akarpov/shortener/forms.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
from django import forms
|
||||
from django.core.validators import URLValidator
|
||||
|
||||
from akarpov.shortener.models import Link
|
||||
|
||||
|
||||
class LinkForm(forms.ModelForm):
|
||||
source = forms.URLField(
|
||||
max_length=500,
|
||||
widget=forms.TextInput,
|
||||
help_text="Please enter the url of the page",
|
||||
validators=[URLValidator],
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Link
|
||||
fields = ["source"]
|
|
@ -1,4 +1,5 @@
|
|||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from model_utils.models import TimeStampedModel
|
||||
|
||||
|
||||
|
@ -13,6 +14,9 @@ class Link(TimeStampedModel):
|
|||
|
||||
viewed = models.IntegerField(default=0)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse("shortener:view", kwargs={"slug": self.slug})
|
||||
|
||||
def __str__(self):
|
||||
return f"link to {self.source}"
|
||||
|
||||
|
|
10
akarpov/shortener/urls.py
Normal file
10
akarpov/shortener/urls.py
Normal file
|
@ -0,0 +1,10 @@
|
|||
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"),
|
||||
]
|
|
@ -0,0 +1,37 @@
|
|||
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
|
||||
|
||||
|
||||
class ShortLinkCreateView(CreateView):
|
||||
model = Link
|
||||
form_class = LinkForm
|
||||
|
||||
template_name = "shortener/create.html"
|
||||
|
||||
def form_valid(self, form):
|
||||
if self.request.user.is_authenticated:
|
||||
form.instance.creator = self.request.user
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
short_link_create_view = ShortLinkCreateView.as_view()
|
||||
|
||||
|
||||
class LinkDetailView(DetailView):
|
||||
|
||||
template_name = "shortener/view.html"
|
||||
|
||||
def get_object(self, *args, **kwargs):
|
||||
link = get_link_from_slug(self.kwargs["slug"])
|
||||
if not link:
|
||||
raise ObjectDoesNotExist
|
||||
if link.creator and link.creator != self.request.user:
|
||||
raise PermissionDenied
|
||||
return link
|
||||
|
||||
|
||||
link_detail_view = LinkDetailView.as_view()
|
|
@ -1,4 +1,4 @@
|
|||
{% load static i18n %}<!DOCTYPE html>
|
||||
{% load static i18n active_link_tags %}<!DOCTYPE html>
|
||||
{% get_current_language as LANGUAGE_CODE %}
|
||||
<html lang="{{ LANGUAGE_CODE }}">
|
||||
<head>
|
||||
|
@ -48,31 +48,25 @@
|
|||
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="{% url 'home' %}">Home <span class="visually-hidden">(current)</span></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'about' %}">About</a>
|
||||
</li>
|
||||
{% if request.user.is_authenticated %}
|
||||
<li class="nav-item">
|
||||
{# URL provided by django-allauth/account/urls.py #}
|
||||
<a class="nav-link" href="{% url 'users:detail' request.user.username %}">{% translate "My Profile" %}</a>
|
||||
<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" href="{% url 'account_logout' %}">{% translate "Sign Out" %}</a>
|
||||
<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" href="{% url 'account_signup' %}">{% translate "Sign Up" %}</a>
|
||||
<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" href="{% url 'account_login' %}">{% translate "Sign In" %}</a>
|
||||
<a id="log-in-link" class="nav-link {% active_link 'account_login' %}" href="{% url 'account_login' %}">{% translate "Sign In" %}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
@ -81,9 +75,7 @@
|
|||
</nav>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-dismissible {% if message.tags %}alert-{{ message.tags }}{% endif %}">
|
||||
|
@ -94,21 +86,12 @@
|
|||
{% endif %}
|
||||
|
||||
{% block content %}
|
||||
<p>Use this document as a way to quick start any new project.</p>
|
||||
{% endblock content %}
|
||||
|
||||
</div> <!-- /container -->
|
||||
</div>
|
||||
|
||||
{% block modal %}{% endblock modal %}
|
||||
|
||||
{% block inline_javascript %}
|
||||
{% comment %}
|
||||
Script tags with only code, no src (defer by default). To run
|
||||
with a "defer" so that you run inline code:
|
||||
<script>
|
||||
window.addEventListener('DOMContentLoaded', () => {/* Run whatever you want */});
|
||||
</script>
|
||||
{% endcomment %}
|
||||
{% endblock inline_javascript %}
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -40,32 +40,31 @@
|
|||
<p>{{ post.body|safe }}</p>
|
||||
<div class="mt-4">
|
||||
<hr>
|
||||
<div class="row g-2">
|
||||
<div class="col-md-auto" id="rating">
|
||||
{% if request.user.is_authenticated %}
|
||||
{% autoescape off %} {{ rating_bar }} {% endautoescape %}
|
||||
{% else %}
|
||||
{% if post.rating < 0 %}
|
||||
<div class="success col-auto align-self-center mt-1"> {{ post.rating }}</div>
|
||||
{% elif post.rating == 0 %}
|
||||
<div class="success col-auto align-self-center gray fw-light mt-1"> {{ post.rating }}</div>
|
||||
<div class="row g-2 d-flex">
|
||||
<div class="col-md-auto align-items-center justify-content-center row">
|
||||
<div id="rating" class="col-auto">
|
||||
{% if request.user.is_authenticated %}
|
||||
{% autoescape off %} {{ rating_bar }} {% endautoescape %}
|
||||
{% else %}
|
||||
<div class="success col-auto align-self-center mt-1"> +{{ post.rating }}</div>
|
||||
{% if post.rating < 0 %}
|
||||
<div class="col-auto align-self-center mt-1"> {{ post.rating }}</div>
|
||||
{% elif post.rating == 0 %}
|
||||
<div class="col-auto align-self-center gray fw-light mt-1"> {{ post.rating }}</div>
|
||||
{% else %}
|
||||
<div class="col-auto align-self-center mt-1"> +{{ post.rating }}</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="justify-content-center text-center col-auto">
|
||||
<i class="bi bi-eye"></i> <div class="ms-1">{{ post.post_views | intword }}</div>
|
||||
</div>
|
||||
<div class="col-md-auto mt-2 d-flex justify-content-center text-center col-sm-2">
|
||||
<i class="bi bi-eye align-self-center"></i> <div class="align-self-center ms-1">{{ post.post_views | intword }}</div>
|
||||
<div class="justify-content-center text-center col-auto align-items-center justify-content-center">
|
||||
<i class="bi bi-chat"></i> <div class="ms-1"> {{ post.comment_count }}</div>
|
||||
</div>
|
||||
<div class="col-md-auto mt-2 d-flex justify-content-center text-center col-sm-2">
|
||||
<i class="bi bi-chat align-self-center"></i> <div class="align-self-center ms-1"> {{ post.comment_count }}</div>
|
||||
</div>
|
||||
<div class="col-6 col-sm-2 col-xl-6"></div>
|
||||
<div class="col-md-auto mt-3 col-sm-2 d-flex justify-content-center text-center">
|
||||
Created: {{ post.created|date:"d.m.Y" }} {{ post.created|time:"H:i" }}
|
||||
</div>
|
||||
<div class="col-md-auto mt-3 d-flex justify-content-center text-center">
|
||||
Updated: {{ post.edited|date:"d.m.Y" }} {{ post.edited|time:"H:i" }}
|
||||
<div class="col-md-auto align-items-center justify-content-center row ms-md-auto text-center">
|
||||
<p class="col-auto">Created: {{ post.created|date:"d.m.Y" }} {{ post.created|time:"H:i" }}</p>
|
||||
<p class="col-auto">Updated: {{ post.edited|date:"d.m.Y" }} {{ post.edited|time:"H:i" }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
14
akarpov/templates/shortener/create.html
Normal file
14
akarpov/templates/shortener/create.html
Normal file
|
@ -0,0 +1,14 @@
|
|||
{% extends "base.html" %}
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block content %}
|
||||
<form class="form-horizontal" enctype="multipart/form-data" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form|crispy }}
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<button type="submit" class="btn btn-success">Create</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
6
akarpov/templates/shortener/view.html
Normal file
6
akarpov/templates/shortener/view.html
Normal file
|
@ -0,0 +1,6 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
{{ link }}
|
||||
{% endblock %}
|
|
@ -8,13 +8,6 @@ FROM python as python-build-stage
|
|||
|
||||
ARG BUILD_ENVIRONMENT=local
|
||||
|
||||
# Install apt packages
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
# dependencies for building Python packages
|
||||
build-essential \
|
||||
# psycopg2 dependencies
|
||||
libpq-dev
|
||||
|
||||
|
||||
# Python 'run' stage
|
||||
FROM python as python-run-stage
|
||||
|
@ -29,23 +22,18 @@ ENV BUILD_ENV ${BUILD_ENVIRONMENT}
|
|||
WORKDIR ${APP_HOME}
|
||||
|
||||
# Install required system dependencies
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
# psycopg2 dependencies
|
||||
libpq-dev \
|
||||
# Translations dependencies
|
||||
gettext \
|
||||
# cleaning up unused files
|
||||
&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
RUN apt-get update && \
|
||||
apt-get install -y build-essential libpq-dev gettext libmagic-dev libjpeg-dev zlib1g-dev && \
|
||||
apt-get purge -y --auto-remove -o APT:AutoRemove:RecommendsImportant=false && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN pip install poetry
|
||||
RUN curl -sSL https://install.python-poetry.org | python3 -
|
||||
ENV PATH="/root/.local/bin:$PATH"
|
||||
|
||||
# Configuring poetry
|
||||
RUN poetry config virtualenvs.create false
|
||||
COPY pyproject.toml poetry.lock /
|
||||
|
||||
# Installing requirements
|
||||
RUN poetry install
|
||||
COPY ./pyproject.toml ./poetry.lock /app/
|
||||
RUN poetry install --no-root --only main
|
||||
|
||||
|
||||
COPY ./compose/production/django/entrypoint /entrypoint
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
ARG PYTHON_VERSION=3.11-slim
|
||||
|
||||
# define an alias for the specfic python version used in this file.
|
||||
FROM python:${PYTHON_VERSION} as python
|
||||
|
||||
|
||||
# Python build stage
|
||||
FROM python as python-build-stage
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE 1
|
||||
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
# dependencies for building Python packages
|
||||
build-essential \
|
||||
# psycopg2 dependencies
|
||||
libpq-dev \
|
||||
# cleaning up unused files
|
||||
&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
# Python 'run' stage
|
||||
FROM python as python-run-stage
|
||||
|
||||
ARG BUILD_ENVIRONMENT
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
ENV PYTHONDONTWRITEBYTECODE 1
|
||||
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
# To run the Makefile
|
||||
make \
|
||||
# psycopg2 dependencies
|
||||
libpq-dev \
|
||||
# Translations dependencies
|
||||
gettext \
|
||||
# Uncomment below lines to enable Sphinx output to latex and pdf
|
||||
# texlive-latex-recommended \
|
||||
# texlive-fonts-recommended \
|
||||
# texlive-latex-extra \
|
||||
# latexmk \
|
||||
# cleaning up unused files
|
||||
&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
RUN pip install poetry
|
||||
|
||||
# Configuring poetry
|
||||
RUN poetry config virtualenvs.create false
|
||||
COPY pyproject.toml poetry.lock /
|
||||
|
||||
# Installing requirements
|
||||
RUN poetry install
|
||||
|
||||
|
||||
COPY ./compose/local/docs/start /start-docs
|
||||
RUN sed -i 's/\r$//g' /start-docs
|
||||
RUN chmod +x /start-docs
|
||||
|
||||
WORKDIR /docs
|
|
@ -1,7 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
set -o nounset
|
||||
|
||||
make livehtml
|
|
@ -110,6 +110,7 @@
|
|||
"cacheops",
|
||||
"extra_settings",
|
||||
"drf_chunked_upload",
|
||||
"active_link",
|
||||
# django-cms
|
||||
"cms",
|
||||
"menus",
|
||||
|
@ -514,3 +515,8 @@
|
|||
# ------------------------------------------------------------------------------
|
||||
SHORTENER_ADD_SLUG = True
|
||||
SHORTENER_SLUG_LENGTH = 3
|
||||
|
||||
|
||||
# ACTIVE_LINK
|
||||
# ------------------------------------------------------------------------------
|
||||
ACTIVE_LINK_CSS_CLASS = "active"
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
# 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")),
|
||||
|
|
17
local.yml
17
local.yml
|
@ -37,23 +37,6 @@ services:
|
|||
env_file:
|
||||
- ./.envs/.local/.postgres
|
||||
|
||||
docs:
|
||||
image: akarpov_local_docs
|
||||
container_name: akarpov_local_docs
|
||||
platform: linux/x86_64
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./compose/local/docs/Dockerfile
|
||||
env_file:
|
||||
- ./.envs/.local/.django
|
||||
volumes:
|
||||
- ./docs:/docs:z
|
||||
- ./config:/app/config:z
|
||||
- ./akarpov:/app/akarpov:z
|
||||
ports:
|
||||
- "9000:9000"
|
||||
command: /start-docs
|
||||
|
||||
mailhog:
|
||||
image: mailhog/mailhog:v1.0.0
|
||||
container_name: akarpov_local_mailhog
|
||||
|
|
16
poetry.lock
generated
16
poetry.lock
generated
|
@ -820,6 +820,18 @@ tzdata = {version = "*", markers = "sys_platform == \"win32\""}
|
|||
argon2 = ["argon2-cffi (>=19.1.0)"]
|
||||
bcrypt = ["bcrypt"]
|
||||
|
||||
[[package]]
|
||||
name = "django-active-link"
|
||||
version = "0.1.8"
|
||||
description = "The best way to highlight active links in your Django app."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "django-active-link-0.1.8.tar.gz", hash = "sha256:87aac58cc89913ff3b017b91cb24cda0dbb05945aa46c6a1428d0744b56a3e1f"},
|
||||
{file = "django_active_link-0.1.8-py2.py3-none-any.whl", hash = "sha256:a6a94f92e9150d05be4491e10e5dfb3274c08dd88866081f5f90ea2d738db647"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "django-allauth"
|
||||
version = "0.51.0"
|
||||
|
@ -2031,7 +2043,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"},
|
||||
]
|
||||
|
||||
|
@ -3648,6 +3659,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"},
|
||||
]
|
||||
|
||||
|
@ -3762,4 +3774,4 @@ files = [
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.11"
|
||||
content-hash = "63c03ff6211f20d9ad19aa9761aac2896a70345a441315ea44e09e8e0a370fcc"
|
||||
content-hash = "69ccdf0950f670e050d0ee1985996ab9873538a9a39a72f58adeee63b3ada902"
|
||||
|
|
|
@ -68,6 +68,7 @@ django-sekizai = "^4.0.0"
|
|||
amzqr = "^0.0.1"
|
||||
django-chunked-upload = "^2.0.0"
|
||||
drf-chunked-upload = "^0.5.1"
|
||||
django-active-link = "^0.1.8"
|
||||
|
||||
|
||||
[build-system]
|
||||
|
|
Loading…
Reference in New Issue
Block a user