add fav and repost function

This commit is contained in:
Tan, Kian-ting 2022-11-27 01:34:44 +08:00
parent c5a762a646
commit 715a0a1a07
10 changed files with 229 additions and 46 deletions

1
.gitignore vendored
View file

@ -133,3 +133,4 @@ tmp/restart.txt
# Django # Django
migrations/ migrations/
media/img/ media/img/
db.sqlite3.sqbpro

View file

@ -63,6 +63,8 @@ class Following(models.Model):
) )
class Post(models.Model): class Post(models.Model):
text = models.TextField() text = models.TextField()
poster = models.ForeignKey(User, on_delete=models.CASCADE) poster = models.ForeignKey(User, on_delete=models.CASCADE)
@ -81,3 +83,24 @@ class Post(models.Model):
) )
class Repost(models.Model):
reposter = models.ForeignKey(User, on_delete=models.CASCADE, related_name="reposter")
reposted_post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name="reposted_post")
repost_time = models.DateTimeField(default=timezone.now())
is_read = models.BooleanField(default=False)
class Reply(models.Model):
replyer_post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name="replyer_post")
replyee_post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name="replyee_post")
is_read = models.BooleanField(default=False)
class Fav(models.Model):
favouriter = models.ForeignKey(User, on_delete=models.CASCADE, related_name="favouriter")
favourited_post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name="favourited_post")
favourited_time = models.DateTimeField(default=timezone.now())
is_read = models.BooleanField(default=False)

View file

@ -32,7 +32,10 @@ urlpatterns = [
path('api/get_latest_posts', views.api_get_latest_posts), path('api/get_latest_posts', views.api_get_latest_posts),
path('api/get_previous_posts', views.api_get_previous_posts), path('api/get_previous_posts', views.api_get_previous_posts),
path('user/<username>', views.user_timeline), path('user/<username>', views.user_timeline),
path('api/follow_request/<request_value>/<dest_username>', views.follow_request) path('api/follow_request/<request_value>/<dest_username>', views.api_follow_request),
path('api/repost_request/<post_id>', views.api_repost_request),
path('api/fav_request/<post_id>', views.api_fav_request),
] ]
if settings.DEBUG: if settings.DEBUG:

View file

@ -1,7 +1,7 @@
import json import json
from django.http import HttpResponse, HttpResponseNotAllowed from django.http import HttpResponse, HttpResponseNotAllowed
from django.template import loader from django.template import loader
from .models import User, Post, Following from .models import User, Post, Following, Fav, Repost
from django.utils import timezone from django.utils import timezone
from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.forms import UserCreationForm
from django.shortcuts import redirect from django.shortcuts import redirect
@ -37,12 +37,21 @@ def api_get_previous_posts(request):
older_posts = Post.objects.filter(post_time__lt=oldest_datetime_object).filter(poster=poster).order_by('-id')[:20] older_posts = Post.objects.filter(post_time__lt=oldest_datetime_object).filter(poster=poster).order_by('-id')[:20]
else: else:
pass pass
older_posts_list = [{"id" : o.pk,
"post_time" : datetime.strftime(o.post_time, "%Y-%m-%d %H:%M:%S.%f%z"), is_faved = [Fav.objects.filter(favourited_post=p).filter(favouriter=request.user).__len__() for p in older_posts]
"poster_username" : o.poster.username, is_reposted = [Repost.objects.filter(reposted_post=p).filter(reposter=request.user).__len__() for p in older_posts]
"poster_shown_name":o.poster.shown_name , older_posts_info = zip(older_posts, is_faved, is_reposted)
"text": o.text}
for o in older_posts] older_posts_list = [{"id" : o[0].pk,
"post_time" : datetime.strftime(o[0].post_time, "%Y-%m-%d %H:%M:%S.%f%z"),
"poster_avatar" : o[0].poster.avatar.url,
"poster_username" : o[0].poster.username,
"poster_shown_name":o[0].poster.shown_name ,
"text": o[0].text,
"is_faved" : o[1],
"is_reposted" : o[2],
}
for o in older_posts_info]
if len(list(older_posts)) > 0: if len(list(older_posts)) > 0:
oldest_time = datetime.strftime(list(older_posts)[-1].post_time, "%Y-%m-%d %H:%M:%S.%f%z") oldest_time = datetime.strftime(list(older_posts)[-1].post_time, "%Y-%m-%d %H:%M:%S.%f%z")
else: else:
@ -72,12 +81,20 @@ def api_get_latest_posts(request):
poster = User.objects.get(username=username) poster = User.objects.get(username=username)
newer_posts = Post.objects.filter(post_time__gt=latest_datetime_object).filter(poster=poster).order_by('-id')[:20] newer_posts = Post.objects.filter(post_time__gt=latest_datetime_object).filter(poster=poster).order_by('-id')[:20]
newer_posts_list = [{"id" : o.pk, is_faved = [Fav.objects.filter(favourited_post=p).filter(favouriter=request.user).__len__() for p in newer_posts]
"post_time" : datetime.strftime(o.post_time, "%Y-%m-%d %H:%M:%S.%f%z"), is_reposted = [Repost.objects.filter(reposted_post=p).filter(reposter=request.user).__len__() for p in newer_posts]
"poster_username" : o.poster.username, newer_posts_infp = zip(newer_posts, is_faved, is_reposted)
"poster_shown_name":o.poster.shown_name ,
"text": o.text} newer_posts_list = [{"id" : o[0].pk,
for o in newer_posts] "post_time" : datetime.strftime(o[0].post_time, "%Y-%m-%d %H:%M:%S.%f%z"),
"poster_avatar" : o[0].poster.avatar.url,
"poster_username" : o[0].poster.username,
"poster_shown_name":o[0].poster.shown_name ,
"text": o[0].text,
"is_faved" : o[1],
"is_reposted" : o[2],
}
for o in newer_posts_infp]
return JsonResponse({'newer_posts':newer_posts_list}) return JsonResponse({'newer_posts':newer_posts_list})
else: else:
return HttpResponseNotAllowed('POST') return HttpResponseNotAllowed('POST')
@ -273,7 +290,39 @@ def user_config(request):
def is_custom_avatar_path(old_image_path): def is_custom_avatar_path(old_image_path):
return os.path.exists(old_image_path) and (old_image_path != os.path.abspath("./media/static/default_avatar.png")) return os.path.exists(old_image_path) and (old_image_path != os.path.abspath("./media/static/default_avatar.png"))
def follow_request(request, request_value, dest_username): def api_fav_request(request, post_id):
if request.method != "POST":
return HttpResponseNotAllowed('POST')
current_user = User.objects.get(id=request.user.id)
post = Post.objects.get(id=post_id)
if Fav.objects.filter(favouriter = current_user, favourited_post=post).__len__() > 0:
existed_fav = Fav.objects.filter(favouriter = current_user, favourited_post=post)[0]
existed_fav.delete()
return JsonResponse({'status': "deleted"})
else:
added_fav = Fav(favouriter = current_user, favourited_post=post)
added_fav.save()
return JsonResponse({'status': "faved"})
def api_repost_request(request, post_id):
if request.method != "POST":
return HttpResponseNotAllowed('POST')
current_user = User.objects.get(id=request.user.id)
post = Post.objects.get(id=post_id)
if Repost.objects.filter(reposter = current_user, reposted_post=post).__len__() > 0:
existed_repost = Repost.objects.filter(reposter = current_user, reposted_post=post)[0]
existed_repost.delete()
return JsonResponse({'status': "deleted"})
else:
added_repost = Repost(reposter = current_user, reposted_post=post)
added_repost.save()
return JsonResponse({'status': "reposted"})
def api_follow_request(request, request_value, dest_username):
if request.method != "POST": if request.method != "POST":
return HttpResponseNotAllowed('POST') return HttpResponseNotAllowed('POST')
else: else:
@ -318,6 +367,10 @@ def user_timeline(request, username):
else: else:
viewed_timeline_list = Post.objects.filter(poster = viewed_user.id).filter(privilage = 'public').order_by('-id')[:20] viewed_timeline_list = Post.objects.filter(poster = viewed_user.id).filter(privilage = 'public').order_by('-id')[:20]
is_faved = [Fav.objects.filter(favourited_post=p).filter(favouriter=request.user).__len__() for p in viewed_timeline_list]
is_reposted = [Repost.objects.filter(reposted_post=p).filter(reposter=request.user).__len__() for p in viewed_timeline_list]
viewed_timeline_info = zip(viewed_timeline_list, is_faved, is_reposted)
latest_received_time = timezone.now() latest_received_time = timezone.now()
if len(viewed_timeline_list) > 0: if len(viewed_timeline_list) > 0:
oldest_received_time = list(viewed_timeline_list)[-1].post_time oldest_received_time = list(viewed_timeline_list)[-1].post_time
@ -334,7 +387,7 @@ def user_timeline(request, username):
'user_follower_number': user_follower_number, 'user_follower_number': user_follower_number,
'latest_received_time' : latest_received_time, 'latest_received_time' : latest_received_time,
'oldest_received_time' : oldest_received_time, 'oldest_received_time' : oldest_received_time,
'viewed_timeline_list': viewed_timeline_list, 'viewed_timeline_info': viewed_timeline_info,
} }
return HttpResponse(template.render(context, request)) return HttpResponse(template.render(context, request))
@ -346,6 +399,10 @@ def home(request):
all_i_follow = Following.objects.filter(follower=request.user.id).filter(isapproved="yes") all_i_follow = Following.objects.filter(follower=request.user.id).filter(isapproved="yes")
all_i_follow_and_me = User.objects.filter(Q(id__in = all_i_follow) | Q(id=request.user.id)) all_i_follow_and_me = User.objects.filter(Q(id__in = all_i_follow) | Q(id=request.user.id))
public_timeline_list = Post.objects.filter(poster__in = all_i_follow_and_me).order_by('-id')[:20] public_timeline_list = Post.objects.filter(poster__in = all_i_follow_and_me).order_by('-id')[:20]
is_faved = [Fav.objects.filter(favourited_post=p).filter(favouriter=request.user).__len__() for p in public_timeline_list]
is_reposted = [Repost.objects.filter(reposted_post=p).filter(reposter=request.user).__len__() for p in public_timeline_list]
public_timeline_info = zip(public_timeline_list, is_faved, is_reposted)
latest_received_time = timezone.now() latest_received_time = timezone.now()
@ -359,6 +416,6 @@ def home(request):
context = { context = {
'latest_received_time' : latest_received_time, 'latest_received_time' : latest_received_time,
'oldest_received_time' : oldest_received_time, 'oldest_received_time' : oldest_received_time,
'public_timeline_list': public_timeline_list, 'public_timeline_info': public_timeline_info,
} }
return HttpResponse(template.render(context, request)) return HttpResponse(template.render(context, request))

View file

@ -1,9 +1,40 @@
div.avatar-preview{ .post{
display:flex;
}
.post-content{
flex-direction: row;
}
.timeline-avatar-img{
flex-direction: row;
width:70px;
height:70px;
} }
#avatar-img{ #avatar-img{
width: 200px; width: 150px;
height: 200px; height: 150px;
object-fit: cover; object-fit: cover;
} }
.reply{
filter: grayscale(1);
}
.reply:hover{
filter: grayscale(0);
}
.unchecked{
filter: grayscale(1);
}
.repost:hover{
filter: grayscale(0);
}
.fav:hover{
filter: grayscale(0);
}

View file

@ -137,7 +137,9 @@ body: JSON.stringify({
return item['older_posts'];}) return item['older_posts'];})
.then(posts => {if (posts.length == 0) .then(posts => {if (posts.length == 0)
{$('previous_post_loader').style.display = 'none';} {$('previous_post_loader').style.display = 'none';}
else{posts.forEach(post => appendPostToTheEnd(post)); else{posts.forEach(post =>
appendPostToTheEnd(post));
updateClickedIconEvent();
$('oldest_time').innerHTML = new_oldest_time;}}) $('oldest_time').innerHTML = new_oldest_time;}})
} }
@ -185,6 +187,7 @@ body: JSON.stringify({
$('new_post_notifier').style.display = "none"; $('new_post_notifier').style.display = "none";
var nowTime = new Date(); var nowTime = new Date();
var nowTimeString = nowTime.toISOString(); var nowTimeString = nowTime.toISOString();
updateClickedIconEvent();
$("latest_time").innerHTML = nowTimeString.substring(0,10) + " " + nowTimeString.substring(11,23) + "000+0000"; }); $("latest_time").innerHTML = nowTimeString.substring(0,10) + " " + nowTimeString.substring(11,23) + "000+0000"; });
} }
@ -194,12 +197,16 @@ var new_div = document.createElement("div");
new_div.id = `post-${post.id}`; new_div.id = `post-${post.id}`;
new_div.className = "post"; new_div.className = "post";
post_text_replaced = post.text.replace(/(\r\n|\n\r|\r|\n)/g, "<br>" ); post_text_replaced = post.text.replace(/(\r\n|\n\r|\r|\n)/g, "<br>" );
new_div.innerHTML = `<a href="/user/${post.poster_username}">${post.poster_shown_name}</a> new_div.innerHTML = `
<img class="timeline-avatar-img" width="100" src="${post.poster_avatar}">
<div class="post-content">
<a href="/user/${post.poster_username}">${post.poster_shown_name}</a>
at <a href="/post/${post.id}" class="post-time">${post.post_time}</a><br> at <a href="/post/${post.id}" class="post-time">${post.post_time}</a><br>
${post_text_replaced}<br> ${post_text_replaced}<br>
<span id="reply-${post.id}" value="${post.id}" class="reply"></span> <span id="reply-${post.id}" data-value="${post.id}" class="reply"></span>
- <span id="repost-${post.id}" value="${post.id}" class="repost">🔁</span> - <span id="repost-${post.id}" data-value="${post.id}" class="${(post.is_reposted == "0" ? "unchecked" : "")} repost">🔁</span>
- <span id="fav-${post.id}" value="${post.id}" class="fav"></span>`; - <span id="fav-${post.id}" data-value="${post.id}" class="${(post.is_faved == "0" ? "unchecked" : "")} fav"></span>
</div>`;
new_div_timestamp = new_div.getElementsByClassName('post-time')[0]; new_div_timestamp = new_div.getElementsByClassName('post-time')[0];
@ -220,11 +227,66 @@ public_tl.insertBefore(new_div, $('latest_time').nextSibling);
$("new_post_notifier").addEventListener('click', getLatestPosts); $("new_post_notifier").addEventListener('click', getLatestPosts);
$("previous_post_loader").addEventListener('click', getPreviousPosts); $("previous_post_loader").addEventListener('click', getPreviousPosts);
async function makeRepostRequest(event){
var postId = event.target.getAttribute('data-value');
await fetch(`/api/repost_request/${postId}`, {
method: 'POST',
headers: {
"X-CSRFToken": csrf_token,
'Content-Type': 'application/json',
},
body : ""
}).then(response => response.json())
.then(item => item['status'])
.then(status =>{
if (status == "reposted"){
event.target.classList.remove("unchecked");
}else if (status == "deleted"){
event.target.classList.add("unchecked");
}
});
}
async function makeFavRequest(event){
var postId = event.target.getAttribute('data-value');
await fetch(`/api/fav_request/${postId}`, {
method: 'POST',
headers: {
"X-CSRFToken": csrf_token,
'Content-Type': 'application/json',
},
body : ""
}).then(response => response.json())
.then(item => item['status'])
.then(status =>{
if (status == "faved"){
event.target.classList.remove("unchecked");
}else if (status == "deleted"){
event.target.classList.add("unchecked");
}
});
}
function updateClickedIconEvent(){
var reposted_items = document.getElementsByClassName('repost');
for (var i = 0; i < reposted_items.length; i++) {
reposted_items[i].addEventListener('click', makeRepostRequest);
}
var reposted_items = document.getElementsByClassName('fav');
for (var i = 0; i < reposted_items.length; i++) {
reposted_items[i].addEventListener('click', makeFavRequest);
}
}
updateClickedIconEvent()
if (requestNote["type"] == "home"){ if (requestNote["type"] == "home"){
$("submit_post").addEventListener('click', make_req); $("submit_post").addEventListener('click', make_req);
adjust_post_text(); adjust_post_text();
} }
if (requestNote["type"] == "user"){ if (requestNote["type"] == "user"){
if ($("follow-user-button")){
$("follow-user-button").addEventListener('click', make_follow_req); $("follow-user-button").addEventListener('click', make_follow_req);
} }
}

View file

@ -6,7 +6,7 @@
{% endblock %} {% endblock %}
<meta charset="utf-8"> <meta charset="utf-8">
{% block title %}<title>Khaikang</title> {% block title %}<title>Khaikang</title>
<link type="text/css" rel="stylesheet" href="{% static 'generic.css' %}"></style> <link type="text/css" rel="stylesheet" href="{% static 'generic.css' %}?{% now 'U' %}"></style>
{% endblock %} {% endblock %}
</head> </head>
<body> <body>

View file

@ -36,14 +36,18 @@
<div id="new_post_notifier" value=""></div> <div id="new_post_notifier" value=""></div>
<div id="latest_time" style="display: block;">{{latest_received_time|date:"Y-m-d H:i:s.u"}}+0000</div> <div id="latest_time" style="display: block;">{{latest_received_time|date:"Y-m-d H:i:s.u"}}+0000</div>
{% for public_post in public_timeline_list %} {% for public_post in public_timeline_info %}
<div id="post-{{public_post.id}}" class="post"><a href="/user/{{public_post.poster}}">{{public_post.poster.shown_name}}</a> <div id="post-{{public_post.0.id}}" class="post">
at <a href="/post/{{public_post.id}}" class="post-time">{{public_post.post_time|date:"Y-m-d H:i:s.u"}}+0000</a><br/> <img class="timeline-avatar-img" src="{{public_post.0.poster.avatar.url}}">
{{public_post.text|linebreaksbr}}<br/> <div class="post-content">
<span id="reply-{{public_post.id}}" value="{{public_post.id}}" class="reply">↩️</span> <a href="/user/{{public_post.0.poster}}">{{public_post.0.poster.shown_name}}</a>
- <span id="repost-{{public_post.id}}" value="{{public_post.id}}" class="repost">🔁</span> at <a href="/post/{{public_post.0.id}}" class="post-time">{{public_post.0.post_time|date:"Y-m-d H:i:s.u"}}+0000</a><br/>
- <span id="fav-{{public_post.id}}" value="{{public_post.id}}" class="fav"></span> {{public_post.0.text|linebreaksbr}}<br/>
<span id="reply-{{public_post.0.id}}" data-value="{{public_post.0.id}}" class="reply">↩️</span>
- <span id="repost-{{public_post.0.id}}" data-value="{{public_post.0.id}}" class=" {%if public_post.1 == 0 %} unchecked{% endif %} repost">🔁</span>
- <span id="fav-{{public_post.0.id}}" data-value="{{public_post.0.id}}" class=" {%if public_post.2 == 0 %} unchecked{% endif %} fav"></span>
</div>
</div> </div>
{% endfor %} {% endfor %}
<div id="previous_post_loader">More posts</div> <div id="previous_post_loader">More posts</div>
@ -52,7 +56,7 @@
</div> </div>
<script type="text/javascript" src="{% static 'timeline.js' %}"> <script type="text/javascript" src="{% static 'timeline.js' %}?{% now 'U' %}">

View file

@ -14,6 +14,6 @@
</form> </form>
<script type="text/javascript" src="{% static 'user_config.js'%}"> <script type="text/javascript" src="{% static 'user_config.js'%}?{% now 'U' %}">
</script> </script>
{% endblock %} {% endblock %}

View file

@ -27,14 +27,16 @@ Following: <span class="fo-number">{{user_following_number}}</span> Follower: <s
<div id="new_post_notifier" value=""></div> <div id="new_post_notifier" value=""></div>
<div id="latest_time" style="display: block;">{{latest_received_time|date:"Y-m-d H:i:s.u"}}+0000</div> <div id="latest_time" style="display: block;">{{latest_received_time|date:"Y-m-d H:i:s.u"}}+0000</div>
{% for post in viewed_timeline_list %} {% for post in viewed_timeline_info %}
<div id="post-{{post.id}}" class="post"><a href="/user/{{post.poster}}">{{post.poster.shown_name}}</a> <div id="post-{{post.0.id}}" class="post">
at <a href="/post/{{post.id}}" class="post-time">{{post.post_time|date:"Y-m-d H:i:s.u"}}+0000</a><br/> <img class="timeline-avatar-img"src="{{post.0.poster.avatar.url}}">
{{post.text|linebreaksbr}}<br/> <div class="post-content"><a href="/user/{{post.0.poster}}">{{post.0.poster.shown_name}}</a>
<span id="reply-{{post.id}}" value="{{post.id}}" class="reply">↩️</span> at <a href="/post/{{post.0.id}}" class="post-time">{{post.0.post_time|date:"Y-m-d H:i:s.u"}}+0000</a><br/>
- <span id="repost-{{post.id}}" value="{{post.id}}" class="repost">🔁</span> {{post.0.text|linebreaksbr}}<br/>
- <span id="fav-{{post.id}}" value="{{post.id}}" class="fav"></span> <span id="reply-{{post.0.id}}" data-value="{{post.0.id}}" class="reply">↩️</span>
- <span id="repost-{{post.0.id}}" data-value="{{post.0.id}}" class=" {%if post.1 == 0 %} unchecked{% endif %} repost">🔁</span>
- <span id="fav-{{post.0.id}}" data-value="{{post.0.id}}"class=" {%if post.2 == 0 %}unchecked{% endif %} fav"></span></div>
</div> </div>
{% endfor %} {% endfor %}
<div id="previous_post_loader">More posts</div> <div id="previous_post_loader">More posts</div>
@ -43,7 +45,7 @@ Following: <span class="fo-number">{{user_following_number}}</span> Follower: <s
</div> </div>
<script type="text/javascript" src="{% static 'timeline.js' %}"> <script type="text/javascript" src="{% static 'timeline.js' %}?{% now 'U' %}">