mirror of
https://github.com/pinry/pinry.git
synced 2025-11-17 10:20:39 +01:00
Feature: Add new public user-api and user-profile card in front-end
This commit is contained in:
137
pinry-spa/src/components/UserProfileCard.vue
Normal file
137
pinry-spa/src/components/UserProfileCard.vue
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
<template>
|
||||||
|
<div class="user-profile-card">
|
||||||
|
<div id="user-home-container">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="media">
|
||||||
|
<div class="media-left">
|
||||||
|
<figure class="image is-48x48">
|
||||||
|
<b-skeleton width="48px" height="48px" :active="avatarLoading"></b-skeleton>
|
||||||
|
<img
|
||||||
|
@load="onAvatarLoaded"
|
||||||
|
v-show="!avatarLoading"
|
||||||
|
:src="user.avatar"
|
||||||
|
alt="avatar"
|
||||||
|
>
|
||||||
|
</figure>
|
||||||
|
</div>
|
||||||
|
<div class="media-content" v-show="!avatarLoading">
|
||||||
|
<p class="title is-4">{{ user.username }}</p>
|
||||||
|
<p class="subtitle is-6">@{{ location }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
Yet another Pinry user.
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tabs is-toggle">
|
||||||
|
<ul>
|
||||||
|
<li :class="trueFalse2Class(inPins)">
|
||||||
|
<a @click="go2UserPins">
|
||||||
|
<b-icon
|
||||||
|
type="is-dark"
|
||||||
|
icon="image"
|
||||||
|
custom-size="mdi-24px">
|
||||||
|
</b-icon>
|
||||||
|
<span>Pins</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li :class="trueFalse2Class(inBoard)">
|
||||||
|
<a @click="go2UserBoard">
|
||||||
|
<b-icon
|
||||||
|
type="is-dark"
|
||||||
|
icon="folder-multiple-image"
|
||||||
|
custom-size="mdi-24px">
|
||||||
|
</b-icon>
|
||||||
|
<span>Boards</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import api from './api';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'UserProfileCard.vue',
|
||||||
|
props: {
|
||||||
|
username: String,
|
||||||
|
inBoard: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
inPins: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
location: window.location.host,
|
||||||
|
avatarLoading: true,
|
||||||
|
user: {
|
||||||
|
avatar: '',
|
||||||
|
username: '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
beforeMount() {
|
||||||
|
this.initializeUser(this.username);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
go2UserBoard() {
|
||||||
|
this.$router.push(
|
||||||
|
{ name: 'boards4user', params: { username: this.username } },
|
||||||
|
);
|
||||||
|
},
|
||||||
|
go2UserPins() {
|
||||||
|
this.$router.push(
|
||||||
|
{ name: 'user', params: { user: this.username } },
|
||||||
|
);
|
||||||
|
},
|
||||||
|
trueFalse2Class(boolValue) {
|
||||||
|
if (boolValue) {
|
||||||
|
return 'is-active';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
onAvatarLoaded() {
|
||||||
|
this.avatarLoading = false;
|
||||||
|
},
|
||||||
|
initializeUser(username) {
|
||||||
|
const self = this;
|
||||||
|
api.User.fetchUserInfoByName(username).then(
|
||||||
|
(user) => {
|
||||||
|
if (user === null) {
|
||||||
|
self.$router.push(
|
||||||
|
{ name: 'PageNotFound' },
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
self.user.avatar = `//gravatar.com/avatar/${user.gravatar}`;
|
||||||
|
self.user.username = user.username;
|
||||||
|
self.user.meta = user;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
#user-home-container {
|
||||||
|
margin-top: 2rem;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
box-shadow: 5px 5px 2px 1px rgba(0, 0, 255, .1);
|
||||||
|
}
|
||||||
|
@import '../components/utils/grid-layout';
|
||||||
|
@include screen-grid-layout("#user-home-container");
|
||||||
|
</style>
|
||||||
@@ -238,6 +238,23 @@ const User = {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
fetchUserInfoByName(username) {
|
||||||
|
/* returns null if user not logged in */
|
||||||
|
const url = `${API_PREFIX}profile/public-users/?username=${username}`;
|
||||||
|
return new Promise(
|
||||||
|
(resolve) => {
|
||||||
|
axios.get(url).then(
|
||||||
|
(resp) => {
|
||||||
|
const users = resp.data;
|
||||||
|
if (users.length === 0) {
|
||||||
|
return resolve(null);
|
||||||
|
}
|
||||||
|
return resolve(users[0]);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
fetchUserInfo(force = false) {
|
fetchUserInfo(force = false) {
|
||||||
/* returns null if user not logged in */
|
/* returns null if user not logged in */
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="boards-for-user">
|
<div class="boards-for-user">
|
||||||
<PHeader></PHeader>
|
<PHeader></PHeader>
|
||||||
|
<UserProfileCard :in-board="true" :username="filters.boardUsername"></UserProfileCard>
|
||||||
<Boards :filters="filters"></Boards>
|
<Boards :filters="filters"></Boards>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import PHeader from '../components/PHeader.vue';
|
import PHeader from '../components/PHeader.vue';
|
||||||
|
import UserProfileCard from '../components/UserProfileCard.vue';
|
||||||
import Boards from '../components/Boards.vue';
|
import Boards from '../components/Boards.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -18,6 +20,7 @@ export default {
|
|||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
PHeader,
|
PHeader,
|
||||||
|
UserProfileCard,
|
||||||
Boards,
|
Boards,
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="pins-for-user">
|
<div class="pins-for-user">
|
||||||
<PHeader></PHeader>
|
<PHeader></PHeader>
|
||||||
|
<UserProfileCard :in-pins="true" :username="filters.userFilter"></UserProfileCard>
|
||||||
<Pins :pin-filters="filters"></Pins>
|
<Pins :pin-filters="filters"></Pins>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import PHeader from '../components/PHeader.vue';
|
import PHeader from '../components/PHeader.vue';
|
||||||
|
import UserProfileCard from '../components/UserProfileCard.vue';
|
||||||
import Pins from '../components/Pins.vue';
|
import Pins from '../components/Pins.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -18,6 +20,7 @@ export default {
|
|||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
PHeader,
|
PHeader,
|
||||||
|
UserProfileCard,
|
||||||
Pins,
|
Pins,
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
|||||||
@@ -6,6 +6,21 @@ from rest_framework.exceptions import ValidationError
|
|||||||
from users.models import User
|
from users.models import User
|
||||||
|
|
||||||
|
|
||||||
|
class PublicUserSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = User
|
||||||
|
fields = (
|
||||||
|
'username',
|
||||||
|
'gravatar',
|
||||||
|
settings.DRF_URL_FIELD_NAME,
|
||||||
|
)
|
||||||
|
extra_kwargs = {
|
||||||
|
settings.DRF_URL_FIELD_NAME: {
|
||||||
|
"view_name": "public-users:user-detail",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class UserSerializer(serializers.HyperlinkedModelSerializer):
|
class UserSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from django.contrib.auth.decorators import login_required
|
|||||||
from django.http import HttpResponseRedirect, HttpResponseBadRequest, HttpResponse
|
from django.http import HttpResponseRedirect, HttpResponseBadRequest, HttpResponse
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.functional import lazy
|
from django.utils.functional import lazy
|
||||||
|
from django_filters.rest_framework import DjangoFilterBackend
|
||||||
from rest_framework import mixins, routers
|
from rest_framework import mixins, routers
|
||||||
from rest_framework.permissions import BasePermission
|
from rest_framework.permissions import BasePermission
|
||||||
from rest_framework.renderers import JSONRenderer
|
from rest_framework.renderers import JSONRenderer
|
||||||
@@ -20,6 +21,21 @@ def reverse_lazy(name=None, *args):
|
|||||||
return lazy(reverse, str)(name, args=args)
|
return lazy(reverse, str)(name, args=args)
|
||||||
|
|
||||||
|
|
||||||
|
class PublicUserViewSet(
|
||||||
|
mixins.RetrieveModelMixin,
|
||||||
|
mixins.ListModelMixin,
|
||||||
|
GenericViewSet,
|
||||||
|
):
|
||||||
|
serializer_class = UserSerializer
|
||||||
|
filter_backends = (DjangoFilterBackend, )
|
||||||
|
filter_fields = ("username", )
|
||||||
|
pagination_class = None
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
username = self.request.GET.get("username", "")
|
||||||
|
return User.objects.filter(username=username)
|
||||||
|
|
||||||
|
|
||||||
class UserViewSet(
|
class UserViewSet(
|
||||||
mixins.RetrieveModelMixin,
|
mixins.RetrieveModelMixin,
|
||||||
mixins.ListModelMixin,
|
mixins.ListModelMixin,
|
||||||
@@ -87,3 +103,4 @@ def logout_user(request):
|
|||||||
|
|
||||||
drf_router = routers.DefaultRouter()
|
drf_router = routers.DefaultRouter()
|
||||||
drf_router.register(r'users', UserViewSet, basename="user")
|
drf_router.register(r'users', UserViewSet, basename="user")
|
||||||
|
drf_router.register(r'public-users', PublicUserViewSet, basename="public-user")
|
||||||
|
|||||||
Reference in New Issue
Block a user