Compare commits
2 Commits
17806d410b
...
980a5bb14b
Author | SHA1 | Date | |
---|---|---|---|
980a5bb14b | |||
8afd7c5694 |
@ -24,6 +24,7 @@ def create(user, data):
|
|||||||
"name": data["name"],
|
"name": data["name"],
|
||||||
"description": data.get("description", ""),
|
"description": data.get("description", ""),
|
||||||
"closed": data.get("closed", False),
|
"closed": data.get("closed", False),
|
||||||
|
"memberPermissions": ["viewMembers", "viewNoticeboard", "postNoticeboard", "viewProjects", "postProjects"],
|
||||||
}
|
}
|
||||||
result = db.groups.insert_one(group)
|
result = db.groups.insert_one(group)
|
||||||
group["_id"] = result.inserted_id
|
group["_id"] = result.inserted_id
|
||||||
@ -43,6 +44,10 @@ def get_one(user, id):
|
|||||||
group = db.groups.find_one({"_id": id})
|
group = db.groups.find_one({"_id": id})
|
||||||
if not group:
|
if not group:
|
||||||
raise util.errors.NotFound("Group not found")
|
raise util.errors.NotFound("Group not found")
|
||||||
|
if group.get("image"):
|
||||||
|
group["imageUrl"] = uploads.get_presigned_url(
|
||||||
|
"groups/{0}/{1}".format(id, group["image"])
|
||||||
|
)
|
||||||
group["adminUsers"] = list(
|
group["adminUsers"] = list(
|
||||||
db.users.find(
|
db.users.find(
|
||||||
{"_id": {"$in": group.get("admins", [])}}, {"username": 1, "avatar": 1}
|
{"_id": {"$in": group.get("admins", [])}}, {"username": 1, "avatar": 1}
|
||||||
@ -64,7 +69,7 @@ def update(user, id, update):
|
|||||||
raise util.errors.NotFound("Group not found")
|
raise util.errors.NotFound("Group not found")
|
||||||
if user["_id"] not in group.get("admins", []):
|
if user["_id"] not in group.get("admins", []):
|
||||||
raise util.errors.Forbidden("You're not a group admin")
|
raise util.errors.Forbidden("You're not a group admin")
|
||||||
allowed_keys = ["name", "description", "closed"]
|
allowed_keys = ["name", "description", "closed", "memberPermissions", "image"]
|
||||||
updater = util.build_updater(update, allowed_keys)
|
updater = util.build_updater(update, allowed_keys)
|
||||||
if updater:
|
if updater:
|
||||||
db.groups.update_one({"_id": id}, updater)
|
db.groups.update_one({"_id": id}, updater)
|
||||||
|
@ -478,6 +478,8 @@ def group_route(id):
|
|||||||
"name": fields.Str(),
|
"name": fields.Str(),
|
||||||
"description": fields.Str(),
|
"description": fields.Str(),
|
||||||
"closed": fields.Bool(),
|
"closed": fields.Bool(),
|
||||||
|
"memberPermissions": fields.List(fields.Str()),
|
||||||
|
"image": fields.Str(allow_none=True),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
def group_route_put(args, id):
|
def group_route_put(args, id):
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import { Helmet } from 'react-helmet'
|
import { Helmet } from 'react-helmet'
|
||||||
import { Segment, Loader, Menu, Message, Container, Button, Icon, Grid, Card } from 'semantic-ui-react'
|
import { Segment, Loader, Menu, Message, Container, Button, Icon, Grid, Card, Image } from 'semantic-ui-react'
|
||||||
import { Outlet, Link, useParams } from 'react-router-dom'
|
import { Outlet, Link, useParams } from 'react-router-dom'
|
||||||
import { useDispatch, useSelector } from 'react-redux'
|
import { useDispatch, useSelector } from 'react-redux'
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
@ -89,6 +89,8 @@ function Group () {
|
|||||||
<Grid stackable>
|
<Grid stackable>
|
||||||
<Grid.Column computer={4}>
|
<Grid.Column computer={4}>
|
||||||
<Card fluid color='yellow'>
|
<Card fluid color='yellow'>
|
||||||
|
{group.imageUrl &&
|
||||||
|
<Image src={group.imageUrl} wrapped ui={false} />}
|
||||||
{group.description &&
|
{group.description &&
|
||||||
<Card.Content>{group.description}</Card.Content>}
|
<Card.Content>{group.description}</Card.Content>}
|
||||||
{group.closed &&
|
{group.closed &&
|
||||||
|
@ -6,6 +6,7 @@ import { toast } from 'react-toastify'
|
|||||||
import utils from '../../../utils/utils.js'
|
import utils from '../../../utils/utils.js'
|
||||||
import actions from '../../../actions'
|
import actions from '../../../actions'
|
||||||
import api from '../../../api'
|
import api from '../../../api'
|
||||||
|
import FileChooser from '../../includes/FileChooser'
|
||||||
|
|
||||||
const PERMISSIONS = [
|
const PERMISSIONS = [
|
||||||
{ name: 'viewMembers', label: 'Allow members to view other members' },
|
{ name: 'viewMembers', label: 'Allow members to view other members' },
|
||||||
@ -37,6 +38,7 @@ function Settings () {
|
|||||||
dispatch(actions.groups.request(false))
|
dispatch(actions.groups.request(false))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const savePermission = (permissionName, enabled) => {
|
const savePermission = (permissionName, enabled) => {
|
||||||
const permissions = group.memberPermissions || []
|
const permissions = group.memberPermissions || []
|
||||||
const index = permissions.indexOf(permissionName)
|
const index = permissions.indexOf(permissionName)
|
||||||
@ -51,6 +53,7 @@ function Settings () {
|
|||||||
toast.error(err.message)
|
toast.error(err.message)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteGroup = () => {
|
const deleteGroup = () => {
|
||||||
utils.confirm('Really delete this group?', 'You\'ll lose all entries in the group feed and anything else you\'ve added to it.').then(() => {
|
utils.confirm('Really delete this group?', 'You\'ll lose all entries in the group feed and anything else you\'ve added to it.').then(() => {
|
||||||
api.groups.delete(group._id, () => {
|
api.groups.delete(group._id, () => {
|
||||||
@ -61,6 +64,16 @@ function Settings () {
|
|||||||
}, () => {})
|
}, () => {})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updatePicture = (image) => {
|
||||||
|
api.groups.update(group._id, { image }, g => {
|
||||||
|
if (!image) { // Needed to ensure the avatar is immediately unset
|
||||||
|
g.image = null
|
||||||
|
g.imageUrl = null
|
||||||
|
}
|
||||||
|
dispatch(actions.groups.updateGroup(group._id, { image: g.image, imageUrl: g.imageUrl }))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Segment color='blue'>
|
<Segment color='blue'>
|
||||||
@ -76,6 +89,25 @@ function Settings () {
|
|||||||
<Divider hidden />
|
<Divider hidden />
|
||||||
<Form.Button loading={loading} color='teal' icon='check' content='Save changes' onClick={saveGroup} />
|
<Form.Button loading={loading} color='teal' icon='check' content='Save changes' onClick={saveGroup} />
|
||||||
</Form>
|
</Form>
|
||||||
|
|
||||||
|
<Header>Group picture</Header>
|
||||||
|
<p>Upload a picture to represent your group. This will be shown on the group page and may be viewable to both members and non-members.</p>
|
||||||
|
{group.imageUrl &&
|
||||||
|
<div style={{ marginBottom: 10 }}>
|
||||||
|
<img src={group.imageUrl} alt='Group' style={{ maxWidth: 200, borderRadius: 5 }} />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||||
|
{group.imageUrl &&
|
||||||
|
<Button basic color='gray' icon='times' content='Remove image' onClick={() => updatePicture(null)} />
|
||||||
|
}
|
||||||
|
<FileChooser
|
||||||
|
forType='group' forObject={group}
|
||||||
|
trigger={<Button basic color='yellow' icon='image' content='Choose an image' />}
|
||||||
|
accept='image/*' onComplete={f => updatePicture(f.storedName)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</Segment>
|
</Segment>
|
||||||
|
|
||||||
<Segment color='blue'>
|
<Segment color='blue'>
|
||||||
|
Loading…
Reference in New Issue
Block a user