Friendship management added
This commit is contained in:
@@ -23,6 +23,9 @@ class SocialNetworkController {
|
|||||||
this.updateDiaryEntry = this.updateDiaryEntry.bind(this);
|
this.updateDiaryEntry = this.updateDiaryEntry.bind(this);
|
||||||
this.deleteDiaryEntry = this.deleteDiaryEntry.bind(this);
|
this.deleteDiaryEntry = this.deleteDiaryEntry.bind(this);
|
||||||
this.getDiaryEntries = this.getDiaryEntries.bind(this);
|
this.getDiaryEntries = this.getDiaryEntries.bind(this);
|
||||||
|
this.addFriend = this.addFriend.bind(this);
|
||||||
|
this.removeFriend = this.removeFriend.bind(this);
|
||||||
|
this.acceptFriendship = this.acceptFriendship.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
async userSearch(req, res) {
|
async userSearch(req, res) {
|
||||||
@@ -287,6 +290,42 @@ class SocialNetworkController {
|
|||||||
res.status(500).json({ error: error.message });
|
res.status(500).json({ error: error.message });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async addFriend(req, res) {
|
||||||
|
try {
|
||||||
|
const { userid: hashedUserid } = req.headers;
|
||||||
|
const { friendUserid } = req.body;
|
||||||
|
await this.socialNetworkService.addFriend(hashedUserid, friendUserid);
|
||||||
|
res.status(201).json({ message: 'added' });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error in addFriend:', error);
|
||||||
|
res.status(500).json({ error: error.message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async removeFriend(req, res) {
|
||||||
|
try {
|
||||||
|
const { userid: hashedUserid } = req.headers;
|
||||||
|
const { friendUserid } = req.params;
|
||||||
|
await this.socialNetworkService.removeFriend(hashedUserid, friendUserid);
|
||||||
|
res.status(200).json({ message: 'removed' });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error in removeFriend:', error);
|
||||||
|
res.status(500).json({ error: error.message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async acceptFriendship(req, res) {
|
||||||
|
try {
|
||||||
|
const { userid: hashedUserid } = req.headers;
|
||||||
|
const { friendUserid } = req.params;
|
||||||
|
await this.socialNetworkService.acceptFriendship(hashedUserid, friendUserid);
|
||||||
|
res.status(200).json({ message: 'accepted' });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error in acceptFriendship:', error);
|
||||||
|
res.status(500).json({ error: error.message });
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default SocialNetworkController;
|
export default SocialNetworkController;
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import TitleHistory from './forum/title_history.js';
|
|||||||
import ForumPermission from './forum/forum_permission.js';
|
import ForumPermission from './forum/forum_permission.js';
|
||||||
import ForumUserPermission from './forum/forum_user_permission.js';
|
import ForumUserPermission from './forum/forum_user_permission.js';
|
||||||
import ForumForumPermission from './forum/forum_forum_permission.js';
|
import ForumForumPermission from './forum/forum_forum_permission.js';
|
||||||
|
import Friendship from './community/friendship.js';
|
||||||
|
|
||||||
export default function setupAssociations() {
|
export default function setupAssociations() {
|
||||||
// UserParam related associations
|
// UserParam related associations
|
||||||
@@ -156,4 +157,9 @@ export default function setupAssociations() {
|
|||||||
|
|
||||||
ForumPermission.hasMany(ForumUserPermission, { foreignKey: 'permissionId' });
|
ForumPermission.hasMany(ForumUserPermission, { foreignKey: 'permissionId' });
|
||||||
ForumUserPermission.belongsTo(ForumPermission, { foreignKey: 'permissionId' });
|
ForumUserPermission.belongsTo(ForumPermission, { foreignKey: 'permissionId' });
|
||||||
|
|
||||||
|
Friendship.belongsTo(User, { foreignKey: 'user1Id', as: 'friendSender' });
|
||||||
|
Friendship.belongsTo(User, { foreignKey: 'user2Id', as: 'friendReceiver' });
|
||||||
|
User.hasMany(Friendship, { foreignKey: 'user1Id', as: 'friendSender' });
|
||||||
|
User.hasMany(Friendship, { foreignKey: 'user2Id', as: 'friendReceiver' });
|
||||||
}
|
}
|
||||||
|
|||||||
37
backend/models/community/friendship.js
Normal file
37
backend/models/community/friendship.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { sequelize } from '../../utils/sequelize.js';
|
||||||
|
import { DataTypes } from 'sequelize';
|
||||||
|
|
||||||
|
const Friendship = sequelize.define('friendship', {
|
||||||
|
id: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
primaryKey: true,
|
||||||
|
autoIncrement: true
|
||||||
|
},
|
||||||
|
user1Id: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false
|
||||||
|
},
|
||||||
|
user2Id: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false
|
||||||
|
},
|
||||||
|
accepted: {
|
||||||
|
type: DataTypes.BOOLEAN,
|
||||||
|
defaultValue: false
|
||||||
|
},
|
||||||
|
denied: {
|
||||||
|
type: DataTypes.BOOLEAN,
|
||||||
|
defaultValue: false
|
||||||
|
},
|
||||||
|
withdrawn: {
|
||||||
|
type: DataTypes.BOOLEAN,
|
||||||
|
defaultValue: false
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
tableName: 'friendship',
|
||||||
|
schema: 'community',
|
||||||
|
underscored: true,
|
||||||
|
timestamps: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default Friendship;
|
||||||
@@ -31,6 +31,7 @@ import Message from './forum/message.js';
|
|||||||
import MessageHistory from './forum/message_history.js';
|
import MessageHistory from './forum/message_history.js';
|
||||||
import MessageImage from './forum/message_image.js';
|
import MessageImage from './forum/message_image.js';
|
||||||
import ForumForumPermission from './forum/forum_forum_permission.js';
|
import ForumForumPermission from './forum/forum_forum_permission.js';
|
||||||
|
import Friendship from './community/friendship.js';
|
||||||
|
|
||||||
const models = {
|
const models = {
|
||||||
SettingsType,
|
SettingsType,
|
||||||
@@ -66,6 +67,7 @@ const models = {
|
|||||||
Message,
|
Message,
|
||||||
MessageHistory,
|
MessageHistory,
|
||||||
MessageImage,
|
MessageImage,
|
||||||
|
Friendship,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default models;
|
export default models;
|
||||||
|
|||||||
@@ -7,25 +7,30 @@ const upload = multer();
|
|||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const socialNetworkController = new SocialNetworkController();
|
const socialNetworkController = new SocialNetworkController();
|
||||||
|
|
||||||
router.post('/usersearch', authenticate, socialNetworkController.userSearch);
|
router.use(authenticate);
|
||||||
router.get('/profile/main/:userId', authenticate, socialNetworkController.profile);
|
|
||||||
router.post('/folders/:folderId', authenticate, socialNetworkController.createFolder);
|
router.post('/usersearch', socialNetworkController.userSearch);
|
||||||
router.get('/folders', authenticate, socialNetworkController.getFolders);
|
router.get('/profile/main/:userId', socialNetworkController.profile);
|
||||||
router.get('/folder/:folderId', authenticate, socialNetworkController.getFolderImageList);
|
router.post('/folders/:folderId', socialNetworkController.createFolder);
|
||||||
router.post('/images', authenticate, upload.single('image'), socialNetworkController.uploadImage);
|
router.get('/folders', socialNetworkController.getFolders);
|
||||||
router.get('/images/:imageId', authenticate, socialNetworkController.getImage);
|
router.get('/folder/:folderId', socialNetworkController.getFolderImageList);
|
||||||
router.put('/images/:imageId', authenticate, socialNetworkController.changeImage);
|
router.post('/images', upload.single('image'), socialNetworkController.uploadImage);
|
||||||
router.get('/imagevisibilities', authenticate, socialNetworkController.getImageVisibilityTypes);
|
router.get('/images/:imageId', socialNetworkController.getImage);
|
||||||
router.get('/image/:hash', authenticate, socialNetworkController.getImageByHash);
|
router.put('/images/:imageId', socialNetworkController.changeImage);
|
||||||
router.get('/profile/images/folders/:username', authenticate, socialNetworkController.getFoldersByUsername);
|
router.get('/imagevisibilities', socialNetworkController.getImageVisibilityTypes);
|
||||||
router.delete('/folders/:folderId', authenticate, socialNetworkController.deleteFolder);
|
router.get('/image/:hash', socialNetworkController.getImageByHash);
|
||||||
router.post('/guestbook/entries', authenticate, upload.single('image'), socialNetworkController.createGuestbookEntry);
|
router.get('/profile/images/folders/:username', socialNetworkController.getFoldersByUsername);
|
||||||
router.get('/guestbook/entries/:username/:page', authenticate, socialNetworkController.getGuestbookEntries);
|
router.delete('/folders/:folderId', socialNetworkController.deleteFolder);
|
||||||
router.delete('/guestbook/entries/:entryId', authenticate, socialNetworkController.deleteGuestbookEntry);
|
router.post('/guestbook/entries', upload.single('image'), socialNetworkController.createGuestbookEntry);
|
||||||
router.get('/guestbook/image/:guestbookUserName/:entryId', authenticate, socialNetworkController.getGuestbookImage);
|
router.get('/guestbook/entries/:username/:page', socialNetworkController.getGuestbookEntries);
|
||||||
router.post('/diary', authenticate, socialNetworkController.createDiaryEntry);
|
router.delete('/guestbook/entries/:entryId', socialNetworkController.deleteGuestbookEntry);
|
||||||
router.put('/diary/:diaryEntryId', authenticate, socialNetworkController.updateDiaryEntry);
|
router.get('/guestbook/image/:guestbookUserName/:entryId', socialNetworkController.getGuestbookImage);
|
||||||
router.delete('/diary/:entryId', authenticate, socialNetworkController.deleteDiaryEntry);
|
router.post('/diary', socialNetworkController.createDiaryEntry);
|
||||||
router.get('/diary/:page', authenticate, socialNetworkController.getDiaryEntries);
|
router.put('/diary/:diaryEntryId', socialNetworkController.updateDiaryEntry);
|
||||||
|
router.delete('/diary/:entryId', socialNetworkController.deleteDiaryEntry);
|
||||||
|
router.get('/diary/:page', socialNetworkController.getDiaryEntries);
|
||||||
|
router.post('/friend', socialNetworkController.addFriend);
|
||||||
|
router.delete('/friend/:friendUserId', socialNetworkController.removeFriend);
|
||||||
|
router.put('/friend/:friendUserId', socialNetworkController.acceptFriendship);
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import { JSDOM } from 'jsdom';
|
|||||||
import DOMPurify from 'dompurify';
|
import DOMPurify from 'dompurify';
|
||||||
import sharp from 'sharp';
|
import sharp from 'sharp';
|
||||||
import Diary from '../models/community/diary.js';
|
import Diary from '../models/community/diary.js';
|
||||||
|
import Friendship from '../models/community/friendship.js';
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = path.dirname(__filename);
|
const __dirname = path.dirname(__filename);
|
||||||
@@ -347,7 +348,15 @@ class SocialNetworkService extends BaseService {
|
|||||||
{ model: UserParamType, as: 'paramType' },
|
{ model: UserParamType, as: 'paramType' },
|
||||||
{ model: UserParamVisibility, as: 'param_visibilities', include: [{ model: UserParamVisibilityType, as: 'visibility_type' }] }
|
{ model: UserParamVisibility, as: 'param_visibilities', include: [{ model: UserParamVisibilityType, as: 'visibility_type' }] }
|
||||||
],
|
],
|
||||||
order: [['order_id', 'asc']]
|
order: [['order_id', 'asc']],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: Friendship,
|
||||||
|
as: 'friendSender',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: Friendship,
|
||||||
|
as: 'friendReceiver',
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
@@ -370,9 +379,26 @@ class SocialNetworkService extends BaseService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let friendship = null;
|
||||||
|
if (user.friendSender && user.friendSender.length > 0) {
|
||||||
|
friendship = {
|
||||||
|
isSender: true,
|
||||||
|
accepted: user.friendSender[0].dataValues.accepted,
|
||||||
|
denied: user.friendSender[0].dataValues.denied,
|
||||||
|
withdrawn: user.friendSender[0].dataValues.withdrawn,
|
||||||
|
}
|
||||||
|
} else if (user.friendReceiver && user.friendReceiver.length > 0) {
|
||||||
|
friendship = {
|
||||||
|
isSender: false,
|
||||||
|
accepted: user.friendReceiver[0].dataValues.accepted,
|
||||||
|
denied: user.friendReceiver[0].dataValues.denied,
|
||||||
|
withdrawn: user.friendReceiver[0].dataValues.withdrawn,
|
||||||
|
}
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
username: user.username,
|
username: user.username,
|
||||||
registrationDate: user.registrationDate,
|
registrationDate: user.registrationDate,
|
||||||
|
friendship: friendship,
|
||||||
params: userParams
|
params: userParams
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -707,5 +733,83 @@ class SocialNetworkService extends BaseService {
|
|||||||
});
|
});
|
||||||
return { entries: entries.rows, totalPages: Math.ceil(entries.count / 20) };
|
return { entries: entries.rows, totalPages: Math.ceil(entries.count / 20) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async addFriend(hashedUserid, friendUserid) {
|
||||||
|
const requestingUserId = await this.checkUserAccess(hashedUserid);
|
||||||
|
const friend = await this.loadUserByHash(friendUserid);
|
||||||
|
if (!friend) {
|
||||||
|
throw new Error('notfound');
|
||||||
|
}
|
||||||
|
const friendship = await Friendship.findOne({
|
||||||
|
where: {
|
||||||
|
[Op.or]: [
|
||||||
|
{ user1Id: requestingUserId, user2Id: friend.id },
|
||||||
|
{ user1Id: friend.id, user2Id: requestingUserId }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (friendship) {
|
||||||
|
if (friendship.withdrawn) {
|
||||||
|
friendship.withdrawn = false;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new Error('alreadyexists');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await Friendship.create({ user1Id: requestingUserId, user2Id: friend.id });
|
||||||
|
}
|
||||||
|
return { accepted: false, withdrawn: false, denied: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
async removeFriend(hashedUserid, friendUserid) {
|
||||||
|
const requestingUserId = await this.checkUserAccess(hashedUserid);
|
||||||
|
const friend = await this.loadUserByHash(friendUserid);
|
||||||
|
if (!friend) {
|
||||||
|
throw new Error('notfound');
|
||||||
|
}
|
||||||
|
const friendship = await Friendship.findOne({
|
||||||
|
where: {
|
||||||
|
[Op.or]: [
|
||||||
|
{ user1Id: requestingUserId, user2Id: friend.id },
|
||||||
|
{ user1Id: friend.id, user2Id: requestingUserId }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!friendship) {
|
||||||
|
throw new Error('notfound');
|
||||||
|
}
|
||||||
|
if (friendship.user1Id === requestingUserId) {
|
||||||
|
friendship.update({ withdrawn: true })
|
||||||
|
} else {
|
||||||
|
friendship.update({ denied: true });
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async acceptFriendship(hashedUserid, friendUserid) {
|
||||||
|
const requestingUserId = await this.checkUserAccess(hashedUserid);
|
||||||
|
const friend = await this.loadUserByHash(friendUserid);
|
||||||
|
if (!friend) {
|
||||||
|
throw new Error('notfound');
|
||||||
|
}
|
||||||
|
const friendship = await Friendship.findOne({
|
||||||
|
where: {
|
||||||
|
[Op.or]: [
|
||||||
|
{ user1Id: requestingUserId, user2Id: friend.id },
|
||||||
|
{ user1Id: friend.id, user2Id: requestingUserId }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!friendship) {
|
||||||
|
throw new Error('notfound');
|
||||||
|
}
|
||||||
|
if (friendship.user1Id === requestingUserId && friendship.withdrawn) {
|
||||||
|
friendship.update({ withdrawn: false });
|
||||||
|
} else if (friendship.user2Id === requestingUserId && friendship.denied) {
|
||||||
|
friendship.update({ denied: false, accepted: true });
|
||||||
|
} else {
|
||||||
|
throw new Error('notfound');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
export default SocialNetworkService;
|
export default SocialNetworkService;
|
||||||
|
|||||||
BIN
frontend/public/images/icons/cancel-friendship.png
Normal file
BIN
frontend/public/images/icons/cancel-friendship.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
frontend/public/images/icons/request-friendship.png
Normal file
BIN
frontend/public/images/icons/request-friendship.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
@@ -14,7 +14,9 @@
|
|||||||
<DataPrivacyDialog ref="dataPrivacyDialog" />
|
<DataPrivacyDialog ref="dataPrivacyDialog" />
|
||||||
<ErrorDialog ref="errorDialog" />
|
<ErrorDialog ref="errorDialog" />
|
||||||
<ImprintDialog ref="imprintDialog" />
|
<ImprintDialog ref="imprintDialog" />
|
||||||
<ShowImageDialog ref="showImageDialog" /></div>
|
<ShowImageDialog ref="showImageDialog" />
|
||||||
|
<MessageDialog ref="messageDialog" />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -34,6 +36,7 @@ import DataPrivacyDialog from './dialogues/standard/DataPrivacyDialog.vue';
|
|||||||
import ErrorDialog from './dialogues/standard/ErrorDialog.vue';
|
import ErrorDialog from './dialogues/standard/ErrorDialog.vue';
|
||||||
import ImprintDialog from './dialogues/standard/ImprintDialog.vue';
|
import ImprintDialog from './dialogues/standard/ImprintDialog.vue';
|
||||||
import ShowImageDialog from './dialogues/socialnetwork/ShowImageDialog.vue';
|
import ShowImageDialog from './dialogues/socialnetwork/ShowImageDialog.vue';
|
||||||
|
import MessageDialog from './dialogues/standard/MessageDialog.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
@@ -59,6 +62,7 @@ export default {
|
|||||||
ErrorDialog,
|
ErrorDialog,
|
||||||
ImprintDialog,
|
ImprintDialog,
|
||||||
ShowImageDialog,
|
ShowImageDialog,
|
||||||
|
MessageDialog,
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.$store.dispatch('loadLoginState');
|
this.$store.dispatch('loadLoginState');
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="visible" :class="['dialog-overlay', { 'non-modal': !modal, 'is-active': isActive }]" @click.self="handleOverlayClick">
|
<div v-if="visible" :class="['dialog-overlay', { 'non-modal': !modal, 'is-active': isActive }]"
|
||||||
|
@click.self="handleOverlayClick">
|
||||||
<div class="dialog" :class="{ minimized: minimized }"
|
<div class="dialog" :class="{ minimized: minimized }"
|
||||||
:style="{ width: dialogWidth, height: dialogHeight, top: dialogTop, left: dialogLeft, position: 'absolute' }"
|
:style="{ width: dialogWidth, height: dialogHeight, top: dialogTop, left: dialogLeft, position: 'absolute' }"
|
||||||
v-if="!minimized" ref="dialog">
|
v-if="!minimized" ref="dialog">
|
||||||
@@ -11,7 +12,7 @@
|
|||||||
<span v-if="!modal" class="dialog-minimize" @click="minimize">_</span>
|
<span v-if="!modal" class="dialog-minimize" @click="minimize">_</span>
|
||||||
<span v-if="showClose" class="dialog-close" @click="close">✖</span>
|
<span v-if="showClose" class="dialog-close" @click="close">✖</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="dialog-body">
|
<div class="dialog-body" :style="{ '--dialog-display': display }">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
<div class="dialog-footer">
|
<div class="dialog-footer">
|
||||||
@@ -62,6 +63,10 @@ export default {
|
|||||||
isTitleTranslated: {
|
isTitleTranslated: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
},
|
||||||
|
display: {
|
||||||
|
type: String,
|
||||||
|
default: 'block'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@@ -170,7 +175,7 @@ export default {
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style lang="scss" scoped>
|
||||||
.dialog-overlay {
|
.dialog-overlay {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
@@ -236,9 +241,13 @@ export default {
|
|||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
display: var(--dialog-display);
|
||||||
|
&[style*="--dialog-display: flex"] {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog-footer {
|
dialog-footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
@@ -261,6 +270,7 @@ export default {
|
|||||||
color: #7E471B;
|
color: #7E471B;
|
||||||
border: 1px solid #7E471B;
|
border: 1px solid #7E471B;
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-active {
|
.is-active {
|
||||||
z-index: 990;
|
z-index: 990;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<DialogWidget ref="dialog" :title="$t('socialnetwork.profile.pretitle')" :isTitleTranslated="isTitleTranslated"
|
<DialogWidget ref="dialog" :title="$t('socialnetwork.profile.pretitle')" :isTitleTranslated="isTitleTranslated"
|
||||||
:show-close="true" :buttons="[{ text: 'Ok', action: 'close' }]" :modal="false" @close="closeDialog" height="75%"
|
:show-close="true" :buttons="[{ text: 'Ok', action: 'close' }]" :modal="false" @close="closeDialog" height="75%"
|
||||||
name="UserProfileDialog">
|
name="UserProfileDialog" display="flex">
|
||||||
<div class="dialog-body">
|
<div class="activities">
|
||||||
|
<span>{{ $t(`socialnetwork.friendship.state.${friendshipState}`) }}</span>
|
||||||
|
<img v-if="['none', 'denied', 'withdrawn'].includes(friendshipState)" src="/images/icons/request-friendship.png"
|
||||||
|
@click="handleFriendship()" />
|
||||||
|
<img v-else-if="['accepted', 'open']" src="/images/icons/cancel-friendship.png"
|
||||||
|
@click="handleFriendship()" />
|
||||||
|
</div>
|
||||||
|
<div class="profile-content">
|
||||||
<div>
|
<div>
|
||||||
<ul class="tab-list">
|
<ul class="tab-list">
|
||||||
<li v-for="tab in tabs" :key="tab.name" :class="{ active: activeTab === tab.name }"
|
<li v-for="tab in tabs" :key="tab.name" :class="{ active: activeTab === tab.name }"
|
||||||
@@ -137,6 +144,8 @@ export default {
|
|||||||
menubar: 'edit format table',
|
menubar: 'edit format table',
|
||||||
promotion: false,
|
promotion: false,
|
||||||
},
|
},
|
||||||
|
hasSendFriendshipRequest: false,
|
||||||
|
friendshipState: 'none',
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -148,6 +157,7 @@ export default {
|
|||||||
try {
|
try {
|
||||||
const response = await apiClient.get(`/api/socialnetwork/profile/main/${this.userId}`);
|
const response = await apiClient.get(`/api/socialnetwork/profile/main/${this.userId}`);
|
||||||
this.userProfile = response.data;
|
this.userProfile = response.data;
|
||||||
|
this.setFriendshipStatus(response.data.friendship);
|
||||||
const newTitle = this.$t('socialnetwork.profile.title').replace('<username>', this.userProfile.username);
|
const newTitle = this.$t('socialnetwork.profile.title').replace('<username>', this.userProfile.username);
|
||||||
this.$refs.dialog.updateTitle(newTitle, false);
|
this.$refs.dialog.updateTitle(newTitle, false);
|
||||||
if (this.activeTab === 'images') {
|
if (this.activeTab === 'images') {
|
||||||
@@ -300,7 +310,6 @@ export default {
|
|||||||
},
|
},
|
||||||
async fetchGuestbookImage(guestbookOwnerName, entry) {
|
async fetchGuestbookImage(guestbookOwnerName, entry) {
|
||||||
try {
|
try {
|
||||||
console.log(entry, guestbookOwnerName);
|
|
||||||
const response = await apiClient.get(`/api/socialnetwork/guestbook/image/${guestbookOwnerName}/${entry.id}`, {
|
const response = await apiClient.get(`/api/socialnetwork/guestbook/image/${guestbookOwnerName}/${entry.id}`, {
|
||||||
responseType: 'blob',
|
responseType: 'blob',
|
||||||
});
|
});
|
||||||
@@ -309,11 +318,75 @@ export default {
|
|||||||
console.error('Error fetching image:', error);
|
console.error('Error fetching image:', error);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async handleFriendship() {
|
||||||
|
console.log(this.friendshipState);
|
||||||
|
if (this.friendshipState === 'none') {
|
||||||
|
this.requestFriendship();
|
||||||
|
} else if (this.friendshipState === 'waiting') {
|
||||||
|
this.cancelFriendship();
|
||||||
|
} else if (this.friendshipState === 'accepted') {
|
||||||
|
this.cancelFriendship();
|
||||||
|
} else if (this.friendshipState === 'denied') {
|
||||||
|
this.acceptFriendship();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async requestFriendship() {
|
||||||
|
try {
|
||||||
|
const response = await apiClient.post('/api/socialnetwork/friend', {
|
||||||
|
friendUserid: this.userId,
|
||||||
|
});
|
||||||
|
this.setFriendshipStatus(response.data);
|
||||||
|
this.$root.$refs.messageDialog.open('tr:socialnetwork.friendship.added');
|
||||||
|
} catch(error) {
|
||||||
|
this.$root.$refs.errorDialog.open(`tr:socialnetwork.friendship.error.${error.response.data.error}`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async cancelFriendship() {
|
||||||
|
try {
|
||||||
|
await apiClient.delete(`/api/socialnetwork/friend/${this.userId}`);
|
||||||
|
this.setFriendshipStatus(null);
|
||||||
|
const type = this.friendshipState === 'waiting' ? 'withdrawn' : 'denied'
|
||||||
|
this.$root.$refs.messageDialog.open(`tr:socialnetwork.friendship.${type}`);
|
||||||
|
} catch(error) {
|
||||||
|
this.$root.$refs.errorDialog.open(`tr:socialnetwork.friendship.error.${error.response.data.error}`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async acceptFriendship() {
|
||||||
|
try {
|
||||||
|
await apiClient.put(`/api/socialnetwork/friend/${this.userId}`);
|
||||||
|
this.setFriendshipStatus(null);
|
||||||
|
this.$root.$refs.messageDialog.open('Freundschaftsanfrage akzeptiert');
|
||||||
|
} catch(error) {
|
||||||
|
this.$root.$refs.errorDialog.open(`tr:socialnetwork.friendship.error.${error.response.data.error}`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setFriendshipStatus(friendshipStates) {
|
||||||
|
if (!friendshipStates) {
|
||||||
|
this.friendshipState = 'none';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.hasSendFriendshipRequest = friendshipStates.isSender;
|
||||||
|
if (friendshipStates.accepted) {
|
||||||
|
this.friendshipState = 'accepted'
|
||||||
|
} else if (friendshipStates.denied) {
|
||||||
|
this.friendshipState = 'denied';
|
||||||
|
} else if (friendshipStates.withdrawn) {
|
||||||
|
this.friendshipState = 'withdrawn';
|
||||||
|
} else if (!friendshipStates.isSender) {
|
||||||
|
this.friendshipState = 'open';
|
||||||
|
} else {
|
||||||
|
this.friendshipState = 'waiting';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.dialog-body > div:first-child {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
.tab-list {
|
.tab-list {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -431,4 +504,30 @@ export default {
|
|||||||
.pagination button {
|
.pagination button {
|
||||||
margin: 0 10px;
|
margin: 0 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.activities {
|
||||||
|
background-color: #F9A22C;
|
||||||
|
margin: -20px -20px 0 -20px;
|
||||||
|
height: 26px !important;
|
||||||
|
display: flex !important;
|
||||||
|
flex-direction: row !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activities > span:first-child {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activities > img {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.userprofile-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-content {
|
||||||
|
flex: 1;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
52
frontend/src/dialogues/standard/MessageDialog.vue
Normal file
52
frontend/src/dialogues/standard/MessageDialog.vue
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<template>
|
||||||
|
<DialogWidget ref="dialog" title="message.title" :show-close="true" :buttons="buttons" :modal="true" width="25em"
|
||||||
|
height="15em" name="MessageDialog" :isTitleTranslated=true>
|
||||||
|
<div class="message-content">
|
||||||
|
<p>{{ translatedMessage }}</p>
|
||||||
|
</div>
|
||||||
|
</DialogWidget>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import DialogWidget from '@/components/DialogWidget.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'MessageDialog',
|
||||||
|
components: {
|
||||||
|
DialogWidget,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
message: '',
|
||||||
|
buttons: [
|
||||||
|
{ text: 'message.close', action: 'close' }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
translatedMessage() {
|
||||||
|
if (this.message.startsWith('tr:')) {
|
||||||
|
return this.$t(this.message.substring(3));
|
||||||
|
}
|
||||||
|
return this.message;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
open(message) {
|
||||||
|
this.message = message;
|
||||||
|
this.$refs.dialog.open();
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
this.$refs.dialog.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.message-content {
|
||||||
|
padding: 1em;
|
||||||
|
color: #000000;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -231,6 +231,23 @@
|
|||||||
"page": "Seite <<page>> von <<of>>"
|
"page": "Seite <<page>> von <<of>>"
|
||||||
},
|
},
|
||||||
"createNewMesssage": "Antwort senden"
|
"createNewMesssage": "Antwort senden"
|
||||||
|
},
|
||||||
|
"friendship": {
|
||||||
|
"error": {
|
||||||
|
"alreadyexists": "Die Freundschaftsanfrage existiert bereits"
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"none": "Nicht befreundet",
|
||||||
|
"waiting": "Freundschaftsanfrage gesendet, aber nicht beantwortet",
|
||||||
|
"open": "Freundschaft wurde angefragt",
|
||||||
|
"denied": "Freundschaftsanfrage abgelehnt",
|
||||||
|
"withdrawn": "Freundschaftsanfrage zurückgezogen",
|
||||||
|
"accepted": "Befreundet"
|
||||||
|
},
|
||||||
|
"added": "Du hast eine Freundschaftsanfrage gestellt.",
|
||||||
|
"withdrawn": "Du hast Deine Freundschaftsanfrage zurückgezogen.",
|
||||||
|
"denied": "Du hast die Freundschaftsanfrage abgelehnt.",
|
||||||
|
"accepted": "Die Freundschaft wurde geschlossen."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user