mirror of
https://github.com/wassname/talk.git
synced 2026-07-06 05:17:19 +08:00
Avatar plugin support extending fragments
This commit is contained in:
@@ -13,4 +13,5 @@ plugins/*
|
||||
!plugins/coral-plugin-viewing-options
|
||||
!plugins/coral-plugin-comment-content
|
||||
!plugins/talk-plugin-permalink
|
||||
!plugins/talk-plugin-avatar
|
||||
node_modules
|
||||
|
||||
@@ -26,5 +26,6 @@ plugins/*
|
||||
!plugins/coral-plugin-viewing-options
|
||||
!plugins/coral-plugin-comment-content
|
||||
!plugins/talk-plugin-permalink
|
||||
!plugins/talk-plugin-avatar
|
||||
|
||||
**/node_modules/*
|
||||
|
||||
@@ -10,7 +10,8 @@ const pluginFragments = getSlotsFragments([
|
||||
'commentInfoBar',
|
||||
'commentActions',
|
||||
'commentContent',
|
||||
'commentReactions'
|
||||
'commentReactions',
|
||||
'commentAvatar'
|
||||
]);
|
||||
|
||||
export default withFragments({
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export {default as withReaction} from './withReaction';
|
||||
export {default as withFragments} from 'coral-framework/hocs/withFragments';
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"presets": [
|
||||
"es2015"
|
||||
],
|
||||
"plugins": [
|
||||
"add-module-exports",
|
||||
"transform-class-properties",
|
||||
"transform-decorators-legacy",
|
||||
"transform-object-assign",
|
||||
"transform-object-rest-spread",
|
||||
"transform-async-to-generator",
|
||||
"transform-react-jsx"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true,
|
||||
"mocha": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"sourceType": "module",
|
||||
"ecmaFeatures": {
|
||||
"experimentalObjectRestSpread": true,
|
||||
"jsx": true
|
||||
}
|
||||
},
|
||||
"parser": "babel-eslint",
|
||||
"plugins": [
|
||||
"react"
|
||||
],
|
||||
"rules": {
|
||||
"react/jsx-uses-react": "error",
|
||||
"react/jsx-uses-vars": "error",
|
||||
"no-console": ["warn", { "allow": ["warn", "error"] }]
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 8.6 KiB |
@@ -0,0 +1,8 @@
|
||||
import React from 'react';
|
||||
import styles from './styles.css';
|
||||
import avatarPlaceholder from '../assets/avatar-placeholder.png';
|
||||
|
||||
const UserAvatar = ({comment: {user}}) =>
|
||||
<img src={!user.avatar ? avatarPlaceholder : user.avatar} className={styles.avatarPlaceholder} />
|
||||
|
||||
export default UserAvatar;
|
||||
@@ -0,0 +1,4 @@
|
||||
.avatarPlaceholder {
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import {gql} from 'react-apollo';
|
||||
import {withFragments} from 'plugin-api/beta/client/hocs';
|
||||
import UserAvatar from '../components/UserAvatar';
|
||||
|
||||
export default withFragments({
|
||||
comment: gql`
|
||||
fragment UserAvatar_comment on Comment {
|
||||
user {
|
||||
avatar
|
||||
}
|
||||
}`
|
||||
})(UserAvatar);
|
||||
@@ -0,0 +1,7 @@
|
||||
import UserAvatar from './components/UserAvatar';
|
||||
|
||||
export default {
|
||||
slots: {
|
||||
commentAvatar: [UserAvatar]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
// We need the UserModel because we need to update the user.
|
||||
const UserModel = require('models/user');
|
||||
|
||||
// Get some middleware to use with the webhook.
|
||||
const auth = require('middleware/authentication');
|
||||
const authz = require('middleware/authorization');
|
||||
|
||||
// Load some config from the environment. This could be changed to a settings
|
||||
// option later if you want to go that route.
|
||||
const DEFAULT_AVATAR = process.env.DEFAULT_AVATAR;
|
||||
|
||||
module.exports = {
|
||||
|
||||
// The new type definitions provides the new "avatar" field needed to inject
|
||||
// into the User type.
|
||||
typeDefs: `
|
||||
type User {
|
||||
avatar: String
|
||||
}
|
||||
`,
|
||||
|
||||
// The User resolver will return the avatar from the embedded user metadata.
|
||||
resolvers: {
|
||||
User: {
|
||||
avatar(user) {
|
||||
if (user && user.metadata && user.metadata.avatar) {
|
||||
return user.metadata.avatar;
|
||||
}
|
||||
|
||||
return DEFAULT_AVATAR;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// The custom router routes that we add here will allow an external system to
|
||||
// update the avatar when it changes on the remote system. Note that we do
|
||||
// use the auth/authz middleware, checking for the ADMIN role. This can be
|
||||
// used in conjunction with a personal access token generated from an ADMIN.
|
||||
router(router) {
|
||||
router.post('/webhooks/user_update', auth, authz.needed('ADMIN'), async (req, res, next) => {
|
||||
|
||||
// We expect that the payload for the new avatar is in the following form:
|
||||
//
|
||||
// {
|
||||
// "id": "123123-123123-12312313",
|
||||
// "avatar": "https://great-cdn.cloudfront.net/best-photo.jpg"
|
||||
// ...
|
||||
// }
|
||||
|
||||
|
||||
// Extract the data from the payload.
|
||||
let {
|
||||
id,
|
||||
avatar
|
||||
} = req.body;
|
||||
|
||||
try {
|
||||
|
||||
// Update the user model.
|
||||
await UserModel.update({id}, {
|
||||
$set: {
|
||||
'metadata.avatar': avatar
|
||||
}
|
||||
});
|
||||
|
||||
} catch (e) {
|
||||
return next(e);
|
||||
}
|
||||
|
||||
// Respond with a `202 Accepted` to indicate that we were able to process
|
||||
// the update.
|
||||
res.status(202).end()
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "talk-plugin-avatar",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "Belen Curcio <curciobelen@gmail.com>",
|
||||
"license": "ISC"
|
||||
}
|
||||
Reference in New Issue
Block a user