Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvement/subscription date in profile #733

Merged
2 changes: 2 additions & 0 deletions club/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@
PEOPLE_PAGE_SIZE = 18
PROFILE_COMMENTS_PAGE_SIZE = 100
PROFILE_POSTS_PAGE_SIZE = 30
FRIENDS_PAGE_SIZE = 30
PROFILE_BADGES_PAGE_SIZE = 50

COMMUNITY_APPROVE_UPVOTES = 35
Expand Down Expand Up @@ -258,6 +259,7 @@

WEBHOOK_SECRETS = set(os.getenv("WEBHOOK_SECRETS", "").split(","))

DEFAULT_AVATAR = "https://i.vas3k.club/v.png"
COMMENT_EDITABLE_TIMEDELTA = timedelta(hours=24)
COMMENT_DELETABLE_TIMEDELTA = timedelta(days=10 * 365)
COMMENT_DELETABLE_BY_POST_AUTHOR_TIMEDELTA = timedelta(days=14)
Expand Down
4 changes: 2 additions & 2 deletions club/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from search.views import search
from users.api import api_profile
from users.views.delete_account import request_delete_account, confirm_delete_account
from users.views.friends import toggle_friend
from users.views.friends import toggle_friend, friends
from users.views.messages import on_review, rejected, banned
from users.views.profile import profile, toggle_tag, add_expertise, delete_expertise, profile_comments, profile_posts, \
profile_badges
Expand All @@ -42,7 +42,6 @@

POST_TYPE_RE = r"(?P<post_type>(all|{}))".format("|".join(dict(Post.TYPES).keys()))
ORDERING_RE = r"(?P<ordering>(activity|new|top|top_week|top_month|hot))"

urlpatterns = [
path("", auth_switch(landing, feed), name="index"),

Expand All @@ -67,6 +66,7 @@
path("user/<slug:user_slug>/posts/", profile_posts, name="profile_posts"),
path("user/<slug:user_slug>/badges/", profile_badges, name="profile_badges"),
path("user/<slug:user_slug>/friend/", toggle_friend, name="toggle_friend"),
path("user/<slug:user_slug>/friends/", friends, name="friends"),
path("user/<slug:user_slug>/edit/", profile_settings, name="profile_settings"),
path("user/<slug:user_slug>/edit/profile/", edit_profile, name="edit_profile"),
path("user/<slug:user_slug>/edit/account/", edit_account, name="edit_account"),
Expand Down
47 changes: 47 additions & 0 deletions frontend/html/users/friends/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{% extends "layout.html" %}
{% load static %}
{% load paginator %}

{% block title %}
Мои чуваки
{% endblock %}

{% block og_tags %}
<meta property="og:title" content="Мои чуваки — {{ settings.APP_NAME }}">
<meta property="og:site_name" content="{{ settings.APP_NAME }}">
<meta property="og:url" content="{{ settings.APP_HOST }}">
<meta property="og:type" content="website" />
<meta property="og:description" content="">
<meta property="og:image" content="🤝">

<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Мои чуваки — {{ settings.APP_NAME }}">
<meta name="twitter:description" content="">
<meta name="twitter:image" content="🤝">

<!-- Exclude friends from search engines -->
<meta name="robots" content="noindex">
{% endblock %}


{% block content %}
<div class="friends">
<div class="friends-title">🤝<br>Мои чуваки</div>

<div class="friends-description">
Это твои чуваки. Их новые посты и комментарии будут приходить тебе уведомлениями в боте.
</div>

{% if friends_paginated %}
<div class="">
{% for user in friends_paginated %}
{% include "users/widgets/card.html" with user=user.user_to %}
{% endfor %}

{% paginator friends_paginated %}
</div>
{% else %}
<div class="friends-results-placeholder">😖 Никого не найдено...</div>
{% endif %}
</div>
{% endblock %}
42 changes: 30 additions & 12 deletions frontend/html/users/profile.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{% load static %}
{% load comments %}
{% load posts %}
{% load users %}
{% load text_filters %}
{% load paginator %}

Expand Down Expand Up @@ -56,11 +57,11 @@
<span class="profile-status-number">{% if user.membership_days_left < 10 %}😱{% else %}😋{% endif %} {{ user.membership_days_left | ceil | cool_number }}</span>
<span class="profile-status-text">{{ user.membership_days_left | ceil | rupluralize:"день,дня,дней" }}</span>
{% elif user.membership_days_left < 700 %}
<span class="profile-status-number">😎 {{ user.membership_months_left | floor | cool_number }}</span>
<span class="profile-status-text">{{ user.membership_months_left | floor | rupluralize:"месяц,месяца,месяцев" }}</span>
<span class="profile-status-number">😎 {{ user.membership_days_left | days_to_months | cool_number }}</span>
<span class="profile-status-text">{{ user.membership_days_left | days_to_months | rupluralize:"месяц,месяца,месяцев" }}</span>
{% else %}
<span class="profile-status-number">💎 {{ user.membership_years_left | floor | cool_number }}</span>
<span class="profile-status-text">{{ user.membership_years_left | floor | rupluralize:"год,года,лет" }}</span>
<span class="profile-status-number">💎 {{ user.membership_days_left | days_to_years | cool_number }}</span>
<span class="profile-status-text">{{ user.membership_days_left | days_to_years | rupluralize:"год,года,лет" }}</span>
{% endif %}
</a>
<a href="{% url "edit_notifications" user.slug %}" class="profile-status">
Expand Down Expand Up @@ -93,16 +94,33 @@
</a>
</div>
{% else %}
<div class="profile-statuses">
<div class="profile-friend-button">
<friend-button
url="{% url "toggle_friend" user.slug %}"
{% if friend %}is-friend-by-default{% endif %}>
</friend-button>
<div class="block profile-statuses">
<div class="profile-status profile-respect">
<span class="profile-status-number">+{{ user.upvotes | cool_number }}</span>
<span class="profile-status-text">
{% if user.upvotes > 1000 %}
плюсиков
{% else %}
{{ user.upvotes | rupluralize:"плюсик,плюсика,плюсиков" }}
{% endif %}
</span>
</div>
<div class="profile-friend-button-comment">
&larr; тестируем бета-версию подписки на все посты и комменты юзера через бота
<div class="profile-status">
{% if user.membership_created_days < 150 %}
<span class="profile-status-number">⏳ {{ user.membership_created_days | ceil | cool_number }}</span>
<span class="profile-status-text">{{ user.membership_created_days | ceil | rupluralize:"день,дня,дней" }} в Клубе</span>
{% elif user.membership_created_days < 700 %}
<span class="profile-status-number">⏳ {{ user.membership_created_days | days_to_months | cool_number }}</span>
<span class="profile-status-text">{{ user.membership_created_days | days_to_months | rupluralize:"месяц,месяца,месяцев" }} в Клубе</span>
{% else %}
<span class="profile-status-number">⏳ {{ user.membership_created_days | days_to_years | cool_number }}</span>
<span class="profile-status-text">{{ user.membership_created_days | days_to_years | rupluralize:"год,года,лет" }} в Клубе</span>
{% endif %}
</div>
<friend-button
url="{% url "toggle_friend" user.slug %}"
{% if friend %}is-friend-by-default{% endif %}>
</friend-button>
</div>
{% endif %}

Expand Down
4 changes: 4 additions & 0 deletions frontend/static/css/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@
clear: both;
}

.clickable {
cursor: pointer;
}

.button {
display: inline-block;
padding: 15px 18px;
Expand Down
54 changes: 54 additions & 0 deletions frontend/static/css/components/friends.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
.friends {
padding-top: 40px;
margin: 0 auto;
max-width: var(--max-content-width);
}

.friends-title {
display: block;
font-size: 300%;
text-align: center;
font-weight: 500;
padding-top: 50px;
padding-bottom: 30px;
text-decoration: none;
}

.friends-header {
display: block;
font-size: 250%;
text-align: center;
font-weight: 500;
padding-top: 80px;
padding-bottom: 30px;
text-decoration: none;
max-width: var(--post-width);
margin: 0 auto;
}

.friends-description {
display: block;
font-size: 130%;
text-align: center;
padding-bottom: 30px;
max-width: var(--post-width);
margin: 0 auto;
}

.friends-results {
grid-column-start: 2;
grid-column-end: 3;
grid-row-start: 4;
grid-row-end: 5;
justify-self: start;
z-index: 100;
}

.friends-results-placeholder {
display: block;
width: 100%;
padding: 50px 20px;
text-align: center;
opacity: 0.5;
font-size: 150%;
}
2 changes: 1 addition & 1 deletion frontend/static/css/components/profile.css
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@
display: block;
font-size: 180%;
font-weight: 500;
padding: 10px 0 0;
padding: 0;
}

.profile-status-icon {
Expand Down
1 change: 1 addition & 0 deletions frontend/static/css/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@
@import "./components/comments.css";
@import "./components/compose.css";
@import "./components/stats.css";
@import "./components/friends.css";
@import "./components/badges.css";
14 changes: 8 additions & 6 deletions frontend/static/js/components/FriendButton.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
<template>
<span>
<button class="button friend-button" @click="toggle">
<span v-if="isFriend" class="friend-button-text">✅ Мой чувак</span>
<span v-else class="friend-button-text">🤝 Добавить в мои чуваки</span>
</button>
</span>
<a v-if="isFriend" class="profile-status clickable" @click="toggle">
<span class="profile-status-icon">✅</span>
<span class="profile-status-status">Мой чувак</span>
</a>
<a v-else class="profile-status clickable" @click="toggle">
<span class="profile-status-icon">🤝</span>
<span class="profile-status-status">Добавить в мои чуваки</span>
</a>
</template>

<script>
Expand Down
16 changes: 16 additions & 0 deletions posts/templatetags/text_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ def rupluralize(value, arg="дурак,дурака,дураков"):
def rutypography(value):
return ru_typus(value)


@register.filter
def uncapitalize(value):
if value and isinstance(value, str) and value[0].isupper():
Expand Down Expand Up @@ -141,3 +142,18 @@ def youtube_id(value):
@register.filter()
def jsonify(value):
return json.dumps(value)


@register.filter()
def days_to_weeks(days):
return days // 7


@register.filter()
def days_to_months(days):
return days // 30.5


@register.filter()
def days_to_years(days):
return days // 365
4 changes: 4 additions & 0 deletions users/models/friends.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,7 @@ def delete_friend(cls, user_from, user_to):
@classmethod
def friends_for_user(cls, user_to):
return cls.objects.filter(user_to=user_to).select_related("user_from")

@classmethod
def user_friends(cls, user_from):
return cls.objects.filter(user_from=user_from).select_related("user_to")
13 changes: 4 additions & 9 deletions users/models/user.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import base64
from datetime import datetime, timedelta
from uuid import uuid4

from django.conf import settings
from django.contrib.postgres.fields import ArrayField
from django.db import models
from django.db.models import F
Expand Down Expand Up @@ -51,8 +51,6 @@ class User(models.Model, ModelDiffMixin):
(MODERATION_STATUS_DELETED, MODERATION_STATUS_DELETED),
]

DEFAULT_AVATAR = "https://i.vas3k.club/v.png"

id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
slug = models.CharField(max_length=32, unique=True)

Expand Down Expand Up @@ -147,11 +145,8 @@ def update_last_activity(self):
def membership_days_left(self):
return (self.membership_expires_at - datetime.utcnow()).total_seconds() // 60 // 60 / 24

def membership_months_left(self):
return self.membership_days_left() / 30

def membership_years_left(self):
return self.membership_days_left() / 365
def membership_created_days(self):
return (datetime.utcnow() - self.created_at).days

def increment_vote_count(self):
return User.objects.filter(id=self.id).update(upvotes=F("upvotes") + 1)
Expand All @@ -160,7 +155,7 @@ def decrement_vote_count(self):
return User.objects.filter(id=self.id).update(upvotes=F("upvotes") - 1)

def get_avatar(self):
return self.avatar or self.DEFAULT_AVATAR
return self.avatar or settings.DEFAULT_AVATAR

@property
def is_banned(self):
Expand Down
21 changes: 19 additions & 2 deletions users/views/friends.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from django.http import Http404
from django.shortcuts import get_object_or_404
from django.http import Http404, HttpResponseForbidden
from django.shortcuts import get_object_or_404, render
from django.conf import settings

from auth.helpers import auth_required
from common.request import ajax_request
from common.pagination import paginate
from users.models.friends import Friend
from users.models.user import User

Expand All @@ -29,3 +31,18 @@ def toggle_friend(request, user_slug):
return {
"status": "created" if is_created else "deleted",
}


@auth_required
def friends(request, user_slug):
if request.me.slug != user_slug:
return HttpResponseForbidden()

user = get_object_or_404(User, slug=user_slug)

user_friends = Friend.user_friends(user_from=user)

return render(request, "users/friends/index.html", {
"user": user,
"friends_paginated": paginate(request, user_friends, page_size=settings.FRIENDS_PAGE_SIZE)
})