Change chat access groups
Adjust some client chat feature - Cleanup some stuff - Read and write chatting
This commit is contained in:
parent
e72cebca4a
commit
4929e2b6f6
6
Makefile
6
Makefile
@ -9,8 +9,10 @@ run-dev: | build-dev
|
||||
stop-dev:
|
||||
docker-compose -f docker/docker-compose.dev.yml down
|
||||
|
||||
get-server-shell:
|
||||
docker-compose -f docker/docker-compose.dev.yml run server bash
|
||||
server-shell:
|
||||
docker-compose -f docker/docker-compose.dev.yml run --entrypoint="" server docker/wait-for-dev-dependencies.sh
|
||||
UID=$$(id -u $${USER}) GID=$$(id -g $${USER}) docker-compose -f docker/docker-compose.dev.yml run --entrypoint="" server bash
|
||||
docker-compose -f docker/docker-compose.dev.yml down
|
||||
|
||||
reload-proxy:
|
||||
docker-compose -f docker/docker-compose.dev.yml exec -w /etc/caddy proxy caddy reload
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 0197c762d94c0723b377b0b2773fb329b7ccaeca
|
||||
Subproject commit 76d3f5385e0a76e79d09d573041a0839d8f483d0
|
@ -18,8 +18,14 @@ import { DataStoreService } from '../../core-services/data-store.service';
|
||||
const ChatGroupRelations: RelationDefinition[] = [
|
||||
{
|
||||
type: 'M2M',
|
||||
ownIdKey: 'access_groups_id',
|
||||
ownKey: 'access_groups',
|
||||
ownIdKey: 'read_groups_id',
|
||||
ownKey: 'read_groups',
|
||||
foreignViewModel: ViewGroup
|
||||
},
|
||||
{
|
||||
type: 'M2M',
|
||||
ownIdKey: 'write_groups_id',
|
||||
ownKey: 'write_groups',
|
||||
foreignViewModel: ViewGroup
|
||||
}
|
||||
];
|
||||
|
@ -1,5 +1,10 @@
|
||||
import { animate, state, style, transition, trigger } from '@angular/animations';
|
||||
|
||||
const fadeSpeed = {
|
||||
fast: 200,
|
||||
slow: 600
|
||||
};
|
||||
|
||||
const slideIn = [style({ transform: 'translateX(-85%)' }), animate('600ms ease')];
|
||||
const slideOut = [
|
||||
style({ transform: 'translateX(0)' }),
|
||||
@ -11,9 +16,15 @@ const slideOut = [
|
||||
)
|
||||
];
|
||||
|
||||
export const collapseAndFade = trigger('collapse', [
|
||||
state('in', style({ opacity: 1, height: '100%' })),
|
||||
transition(':enter', [style({ opacity: 0, height: 0 }), animate(fadeSpeed.fast)]),
|
||||
transition(':leave', animate(fadeSpeed.fast, style({ opacity: 0, height: 0 })))
|
||||
]);
|
||||
|
||||
export const fadeAnimation = trigger('fade', [
|
||||
state('in', style({ opacity: 1 })),
|
||||
transition(':enter', [style({ opacity: 0 }), animate(600)]),
|
||||
transition(':leave', animate(600, style({ opacity: 0 })))
|
||||
transition(':enter', [style({ opacity: 0 }), animate(fadeSpeed.slow)]),
|
||||
transition(':leave', animate(fadeSpeed.slow, style({ opacity: 0 })))
|
||||
]);
|
||||
export const navItemAnim = trigger('navItemAnim', [transition(':enter', slideIn), transition(':leave', slideOut)]);
|
||||
|
@ -18,10 +18,6 @@ os-icon-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
& + & {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
&.small-container {
|
||||
@include icon-container(12px, 12px, 400);
|
||||
}
|
||||
|
@ -5,7 +5,8 @@ export class ChatGroup extends BaseModel<ChatGroup> {
|
||||
|
||||
public id: number;
|
||||
public name: string;
|
||||
public access_groups_id: number[];
|
||||
public read_groups_id: number[];
|
||||
public write_groups_id: number[];
|
||||
|
||||
public constructor(input?: any) {
|
||||
super(ChatGroup.COLLECTIONSTRING, input);
|
||||
|
@ -1,17 +1,29 @@
|
||||
<div class="chat-header" *osPerms="permission.chatCanManage">
|
||||
<os-icon-container
|
||||
icon="group"
|
||||
*ngIf="chatGroup.access_groups.length"
|
||||
matTooltip="{{ 'Access groups' | translate }}"
|
||||
*ngIf="chatGroup.write_groups.length"
|
||||
matTooltip="{{ 'Groups with write permissions' | translate }}"
|
||||
>
|
||||
<span *ngFor="let group of chatGroup.access_groups | slice: 0:3; let last = last">
|
||||
<span *ngFor="let group of chatGroup.write_groups | slice: 0:3; let last = last">
|
||||
<span>{{ group.getTitle() | translate }}</span>
|
||||
<span *ngIf="!last">, </span>
|
||||
<span *ngIf="last && chatGroup.access_groups.length > 3">...</span>
|
||||
<span *ngIf="last && chatGroup.write_groups.length > 3">...</span>
|
||||
</span>
|
||||
</os-icon-container>
|
||||
|
||||
<os-icon-container
|
||||
icon="remove_red_eye"
|
||||
*ngIf="readOnlyGroups.length"
|
||||
matTooltip="{{ 'Groups with read permissions' | translate }}"
|
||||
>
|
||||
<span *ngFor="let group of readOnlyGroups | slice: 0:3; let last = last">
|
||||
<span>{{ group.getTitle() | translate }}</span>
|
||||
<span *ngIf="!last">, </span>
|
||||
<span *ngIf="last && chatGroup.read_groups.length > 3">...</span>
|
||||
</span>
|
||||
</os-icon-container>
|
||||
<button class="chat-options" mat-icon-button [matMenuTriggerFor]="chatgroupMenu">
|
||||
<mat-icon> more_vert </mat-icon>
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@ -41,5 +53,4 @@
|
||||
<span>{{ 'Delete' | translate }}</span>
|
||||
</button>
|
||||
</ng-container>
|
||||
<!-- edit -->
|
||||
</mat-menu>
|
||||
|
@ -22,6 +22,7 @@ import { ChatGroup } from 'app/shared/models/chat/chat-group';
|
||||
import { infoDialogSettings } from 'app/shared/utils/dialog-settings';
|
||||
import { BaseViewComponentDirective } from 'app/site/base/base-view';
|
||||
import { ChatNotificationService } from 'app/site/chat/services/chat-notification.service';
|
||||
import { ViewGroup } from 'app/site/users/models/view-group';
|
||||
import {
|
||||
ChatGroupData,
|
||||
EditChatGroupDialogComponent
|
||||
@ -51,6 +52,12 @@ export class ChatGroupDetailComponent extends BaseViewComponentDirective impleme
|
||||
return isOnBottom;
|
||||
}
|
||||
|
||||
public get readOnlyGroups(): ViewGroup[] {
|
||||
const readGroups = this.chatGroup?.read_groups;
|
||||
const writeGrous = this.chatGroup?.write_groups;
|
||||
return readGroups?.filter(group => !writeGrous.includes(group)) || [];
|
||||
}
|
||||
|
||||
public constructor(
|
||||
titleService: Title,
|
||||
protected translate: TranslateService,
|
||||
@ -111,7 +118,8 @@ export class ChatGroupDetailComponent extends BaseViewComponentDirective impleme
|
||||
public editChat(): void {
|
||||
const chatData: ChatGroupData = {
|
||||
name: this.chatGroup.name,
|
||||
access_groups_id: this.chatGroup.access_groups_id
|
||||
read_groups_id: this.chatGroup.read_groups_id,
|
||||
write_groups_id: this.chatGroup.write_groups_id
|
||||
};
|
||||
|
||||
const dialogRef = this.dialog.open(EditChatGroupDialogComponent, {
|
||||
|
@ -4,8 +4,12 @@
|
||||
</div>
|
||||
<div
|
||||
class="chat-text"
|
||||
[ngClass]="{ 'background-primary': !isOwnMessage, 'background-primary-darkest': isOwnMessage }"
|
||||
[matMenuTriggerFor]="canDelete ? singleChatMenu : null"
|
||||
[ngClass]="{
|
||||
disabled: !canDelete,
|
||||
'background-primary': !isOwnMessage,
|
||||
'background-primary-darkest': isOwnMessage
|
||||
}"
|
||||
[matMenuTriggerFor]="singleChatMenu"
|
||||
>
|
||||
{{ text }}
|
||||
<div class="timestamp">{{ date | localizedDate }}</div>
|
||||
|
@ -1,9 +1,9 @@
|
||||
<mat-tab-group (selectedTabChange)="selectedTabChange($event)" *ngIf="chatGroupsExist()">
|
||||
<mat-tab-group (selectedTabChange)="selectedTabChange($event)" *ngIf="chatGroupsExist">
|
||||
<mat-tab *ngFor="let chat of chatGroupSubject | async">
|
||||
<ng-template mat-tab-label>
|
||||
<span
|
||||
[matBadgeHidden]="!getNotidficationsForChatId(chat.id)"
|
||||
[matBadge]="getNotidficationsForChatId(chat.id)"
|
||||
[matBadgeHidden]="!getNotificationsForChatId(chat.id)"
|
||||
[matBadge]="getNotificationsForChatId(chat.id)"
|
||||
matBadgeColor="accent"
|
||||
matBadgeOverlap="false"
|
||||
>
|
||||
@ -16,14 +16,14 @@
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
|
||||
<div *ngIf="!chatGroupsExist()">
|
||||
<div *ngIf="!chatGroupsExist">
|
||||
<span>
|
||||
{{ 'No chat groups available' | translate }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- send chat -->
|
||||
<form [formGroup]="newMessageForm" (ngSubmit)="send()" *ngIf="chatGroupsExist()">
|
||||
<form [formGroup]="newMessageForm" (ngSubmit)="send()" *ngIf="chatGroupsExist && canSendInSelectedChat" [@collapse]>
|
||||
<mat-form-field appearance="outline" class="chat-form-field">
|
||||
<input class="chat-input" type="text" matInput formControlName="text" />
|
||||
<mat-label>{{ 'Message' | translate }}</mat-label>
|
||||
|
@ -7,8 +7,10 @@ import { Title } from '@angular/platform-browser';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
|
||||
import { OperatorService } from 'app/core/core-services/operator.service';
|
||||
import { ChatGroupRepositoryService } from 'app/core/repositories/chat/chat-group-repository.service';
|
||||
import { ChatMessageRepositoryService } from 'app/core/repositories/chat/chat-message-repository.service';
|
||||
import { collapseAndFade } from 'app/shared/animations';
|
||||
import { ChatMessage } from 'app/shared/models/chat/chat-message';
|
||||
import { BaseViewComponentDirective } from 'app/site/base/base-view';
|
||||
import { ChatNotificationService, NotificationAmount } from '../../services/chat-notification.service';
|
||||
@ -18,7 +20,8 @@ import { ViewChatGroup } from '../../models/view-chat-group';
|
||||
selector: 'os-chat-tabs',
|
||||
templateUrl: './chat-tabs.component.html',
|
||||
styleUrls: ['./chat-tabs.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
animations: [collapseAndFade]
|
||||
})
|
||||
export class ChatTabsComponent extends BaseViewComponentDirective implements OnInit {
|
||||
public chatGroupSubject: BehaviorSubject<ViewChatGroup[]>;
|
||||
@ -27,6 +30,21 @@ export class ChatTabsComponent extends BaseViewComponentDirective implements OnI
|
||||
|
||||
private notifications: NotificationAmount;
|
||||
|
||||
private get chatGroupFromIndex(): ViewChatGroup {
|
||||
return this.chatGroupSubject.value[this.selectedTabIndex];
|
||||
}
|
||||
|
||||
public get chatGroupsExist(): boolean {
|
||||
return this.chatGroupSubject.value.length > 0;
|
||||
}
|
||||
|
||||
public get canSendInSelectedChat(): boolean {
|
||||
if (!this.chatGroupFromIndex) {
|
||||
return false;
|
||||
}
|
||||
return this.operator.isInGroupIds(...this.chatGroupFromIndex?.write_groups_id) || false;
|
||||
}
|
||||
|
||||
public constructor(
|
||||
titleService: Title,
|
||||
translate: TranslateService,
|
||||
@ -34,6 +52,7 @@ export class ChatTabsComponent extends BaseViewComponentDirective implements OnI
|
||||
private repo: ChatGroupRepositoryService,
|
||||
private chatMessageRepo: ChatMessageRepositoryService,
|
||||
private chatNotificationService: ChatNotificationService,
|
||||
private operator: OperatorService,
|
||||
formBuilder: FormBuilder
|
||||
) {
|
||||
super(titleService, translate, matSnackBar);
|
||||
@ -55,14 +74,10 @@ export class ChatTabsComponent extends BaseViewComponentDirective implements OnI
|
||||
this.selectedTabIndex = event.index;
|
||||
}
|
||||
|
||||
public getNotidficationsForChatId(chatId: number): number {
|
||||
public getNotificationsForChatId(chatId: number): number {
|
||||
return this.notifications?.[chatId] ?? 0;
|
||||
}
|
||||
|
||||
public chatGroupsExist(): boolean {
|
||||
return this.chatGroupSubject.value.length > 0;
|
||||
}
|
||||
|
||||
public isChatMessageEmpty(): boolean {
|
||||
return !this.newMessageForm?.value?.text?.trim();
|
||||
}
|
||||
@ -70,7 +85,7 @@ export class ChatTabsComponent extends BaseViewComponentDirective implements OnI
|
||||
public send(): void {
|
||||
const payload = {
|
||||
text: this.newMessageForm.value.text,
|
||||
chatgroup_id: this.chatGroupSubject.value[this.selectedTabIndex].id
|
||||
chatgroup_id: this.chatGroupFromIndex.id
|
||||
};
|
||||
this.chatMessageRepo
|
||||
.create(payload as ChatMessage)
|
||||
|
@ -24,9 +24,17 @@
|
||||
<!-- Groups -->
|
||||
<mat-form-field>
|
||||
<os-search-value-selector
|
||||
formControlName="access_groups_id"
|
||||
formControlName="read_groups_id"
|
||||
[multiple]="true"
|
||||
placeholder="{{ 'Access groups' | translate }}"
|
||||
placeholder="{{ 'Groups with read permissions' | translate }}"
|
||||
[inputListValues]="groupsBehaviorSubject"
|
||||
></os-search-value-selector>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<os-search-value-selector
|
||||
formControlName="write_groups_id"
|
||||
[multiple]="true"
|
||||
placeholder="{{ 'Groups with write permissions' | translate }}"
|
||||
[inputListValues]="groupsBehaviorSubject"
|
||||
></os-search-value-selector>
|
||||
</mat-form-field>
|
||||
|
@ -10,7 +10,8 @@ import { ViewGroup } from 'app/site/users/models/view-group';
|
||||
|
||||
export interface ChatGroupData {
|
||||
name: string;
|
||||
access_groups_id: number[];
|
||||
read_groups_id: number[];
|
||||
write_groups_id: number[];
|
||||
}
|
||||
|
||||
@Component({
|
||||
@ -36,7 +37,8 @@ export class EditChatGroupDialogComponent {
|
||||
this.createMode = !data;
|
||||
this.createUpdateForm = formBuilder.group({
|
||||
name: [data?.name || '', Validators.required],
|
||||
access_groups_id: [data?.access_groups_id || []]
|
||||
read_groups_id: [data?.read_groups_id || []],
|
||||
write_groups_id: [data?.write_groups_id || []]
|
||||
});
|
||||
this.groupsBehaviorSubject = groupRepo.getViewModelListBehaviorSubject();
|
||||
}
|
||||
|
@ -15,5 +15,6 @@ export class ViewChatGroup extends BaseViewModel<ChatGroup> implements ChatGroup
|
||||
}
|
||||
}
|
||||
export interface ViewChatGroup extends ChatGroup {
|
||||
access_groups: ViewGroup[];
|
||||
read_groups: ViewGroup[];
|
||||
write_groups: ViewGroup[];
|
||||
}
|
||||
|
@ -18,9 +18,9 @@ export class ChatService {
|
||||
private canSeeSomeChatGroup = false;
|
||||
private canManage = false;
|
||||
|
||||
private canSeeChat = new BehaviorSubject<boolean>(false);
|
||||
private canSeeChatSubject = new BehaviorSubject<boolean>(false);
|
||||
public get canSeeChatObservable(): Observable<boolean> {
|
||||
return this.canSeeChat.asObservable();
|
||||
return this.canSeeChatSubject.asObservable();
|
||||
}
|
||||
|
||||
public constructor(
|
||||
@ -34,7 +34,7 @@ export class ChatService {
|
||||
});
|
||||
|
||||
this.repo.getViewModelListBehaviorSubject().subscribe(groups => {
|
||||
this.canSeeSomeChatGroup = !!groups && groups.length > 0;
|
||||
this.canSeeSomeChatGroup = groups?.length > 0;
|
||||
this.update();
|
||||
});
|
||||
|
||||
@ -45,6 +45,6 @@ export class ChatService {
|
||||
}
|
||||
|
||||
private update(): void {
|
||||
this.canSeeChat.next(this.chatEnabled && (this.canSeeSomeChatGroup || this.canManage));
|
||||
this.canSeeChatSubject.next(this.chatEnabled && (this.canSeeSomeChatGroup || this.canManage));
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ services:
|
||||
- ../server:/app
|
||||
depends_on:
|
||||
- redis
|
||||
- postgres
|
||||
|
||||
postgres:
|
||||
image: postgres:11
|
||||
|
@ -19,12 +19,7 @@ function isSettingsFileOk() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
wait-for-it -t 0 redis:6379
|
||||
|
||||
until pg_isready -h postgres -p 5432 -U openslides; do
|
||||
echo "Waiting for Postgres to become available..."
|
||||
sleep 3
|
||||
done
|
||||
/app/docker/wait-for-dev-dependencies.sh
|
||||
|
||||
if [[ ! -f "/app/personal_data/var/settings.py" ]]; then
|
||||
echo "Create settings"
|
||||
|
10
server/docker/wait-for-dev-dependencies.sh
Executable file
10
server/docker/wait-for-dev-dependencies.sh
Executable file
@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
wait-for-it -t 0 redis:6379
|
||||
|
||||
until pg_isready -h postgres -p 5432 -U openslides; do
|
||||
echo "Waiting for Postgres to become available..."
|
||||
sleep 3
|
||||
done
|
0
server/manage.py
Executable file → Normal file
0
server/manage.py
Executable file → Normal file
@ -7,7 +7,7 @@ from openslides.utils.auth import async_has_perm, async_in_some_groups
|
||||
class ChatGroupAccessPermissions(BaseAccessPermissions):
|
||||
"""
|
||||
Access permissions container for ChatGroup and ChatGroupViewSet.
|
||||
No base perm: The access permissions are done with the access groups
|
||||
No base perm: The access permissions are done with the read/write groups.
|
||||
"""
|
||||
|
||||
async def get_restricted_data(
|
||||
@ -22,10 +22,11 @@ class ChatGroupAccessPermissions(BaseAccessPermissions):
|
||||
data = full_data
|
||||
else:
|
||||
for full in full_data:
|
||||
access_groups = full.get("access_groups_id", [])
|
||||
if len(
|
||||
full.get("access_groups_id", [])
|
||||
) == 0 or await async_in_some_groups(user_id, access_groups):
|
||||
read_groups = full.get("read_groups_id", [])
|
||||
write_groups = full.get("write_groups_id", [])
|
||||
if await async_in_some_groups(
|
||||
user_id, read_groups
|
||||
) or await async_in_some_groups(user_id, write_groups):
|
||||
data.append(full)
|
||||
return data
|
||||
|
||||
|
@ -0,0 +1,33 @@
|
||||
# Generated by Finn Stutzenstein on 2021-02-18 08:12
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("chat", "0001_initial"),
|
||||
("users", "0016_remove_user_ordering"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name="chatgroup",
|
||||
old_name="access_groups",
|
||||
new_name="read_groups",
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="chatgroup",
|
||||
name="read_groups",
|
||||
field=models.ManyToManyField(
|
||||
blank=True, related_name="chat_read_groups", to="users.Group"
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="chatgroup",
|
||||
name="write_groups",
|
||||
field=models.ManyToManyField(
|
||||
blank=True, related_name="chat_write_groups", to="users.Group"
|
||||
),
|
||||
),
|
||||
]
|
@ -0,0 +1,19 @@
|
||||
# Generated by Finn Stutzenstein on 2021-02-18 08:12
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def copy_read_groups_to_write_groups(apps, schema_editor):
|
||||
ChatGroup = apps.get_model("chat", "ChatGroup")
|
||||
|
||||
for chatgroup in ChatGroup.objects.all():
|
||||
chatgroup.write_groups.add(*chatgroup.read_groups.all())
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("chat", "0002_new_access_groups_1"),
|
||||
]
|
||||
|
||||
operations = [migrations.RunPython(copy_read_groups_to_write_groups)]
|
@ -18,7 +18,7 @@ class ChatGroupManager(BaseManager):
|
||||
return (
|
||||
super()
|
||||
.get_prefetched_queryset(*args, **kwargs)
|
||||
.prefetch_related("access_groups")
|
||||
.prefetch_related("read_groups", "write_groups")
|
||||
)
|
||||
|
||||
|
||||
@ -30,8 +30,11 @@ class ChatGroup(RESTModelMixin, models.Model):
|
||||
objects = ChatGroupManager()
|
||||
|
||||
name = models.CharField(max_length=256)
|
||||
access_groups = models.ManyToManyField(
|
||||
settings.AUTH_GROUP_MODEL, blank=True, related_name="chat_access_groups"
|
||||
read_groups = models.ManyToManyField(
|
||||
settings.AUTH_GROUP_MODEL, blank=True, related_name="chat_read_groups"
|
||||
)
|
||||
write_groups = models.ManyToManyField(
|
||||
settings.AUTH_GROUP_MODEL, blank=True, related_name="chat_write_groups"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
@ -41,14 +44,11 @@ class ChatGroup(RESTModelMixin, models.Model):
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def can_access(self, user):
|
||||
def can_write(self, user):
|
||||
if has_perm(user.id, "chat.can_manage"):
|
||||
return True
|
||||
|
||||
if not self.access_groups.exists():
|
||||
return True
|
||||
|
||||
return in_some_groups(user.id, self.access_groups.values_list(flat=True))
|
||||
return in_some_groups(user.id, self.write_groups.values_list(flat=True))
|
||||
|
||||
|
||||
class ChatMessageManager(BaseManager):
|
||||
@ -61,7 +61,9 @@ class ChatMessageManager(BaseManager):
|
||||
return (
|
||||
super()
|
||||
.get_prefetched_queryset(*args, **kwargs)
|
||||
.prefetch_related("chatgroup", "chatgroup__access_groups")
|
||||
.prefetch_related(
|
||||
"chatgroup", "chatgroup__read_groups", "chatgroup__write_groups"
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
@ -14,7 +14,10 @@ class ChatGroupSerializer(ModelSerializer):
|
||||
Serializer for chat.models.ChatGroup objects.
|
||||
"""
|
||||
|
||||
access_groups = IdPrimaryKeyRelatedField(
|
||||
read_groups = IdPrimaryKeyRelatedField(
|
||||
many=True, required=False, queryset=get_group_model().objects.all()
|
||||
)
|
||||
write_groups = IdPrimaryKeyRelatedField(
|
||||
many=True, required=False, queryset=get_group_model().objects.all()
|
||||
)
|
||||
|
||||
@ -23,7 +26,8 @@ class ChatGroupSerializer(ModelSerializer):
|
||||
fields = (
|
||||
"id",
|
||||
"name",
|
||||
"access_groups",
|
||||
"read_groups",
|
||||
"write_groups",
|
||||
)
|
||||
|
||||
|
||||
@ -35,7 +39,8 @@ class ChatMessageSerializer(ModelSerializer):
|
||||
chatgroup = IdPrimaryKeyRelatedField(
|
||||
required=False, queryset=ChatGroup.objects.all()
|
||||
)
|
||||
access_groups_id = SerializerMethodField()
|
||||
read_groups_id = SerializerMethodField()
|
||||
write_groups_id = SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = ChatMessage
|
||||
@ -46,7 +51,8 @@ class ChatMessageSerializer(ModelSerializer):
|
||||
"timestamp",
|
||||
"username",
|
||||
"user_id",
|
||||
"access_groups_id",
|
||||
"read_groups_id",
|
||||
"write_groups_id",
|
||||
)
|
||||
read_only_fields = (
|
||||
"username",
|
||||
@ -58,5 +64,8 @@ class ChatMessageSerializer(ModelSerializer):
|
||||
data["text"] = validate_html_strict(data["text"])
|
||||
return data
|
||||
|
||||
def get_access_groups_id(self, chatmessage):
|
||||
return [group.id for group in chatmessage.chatgroup.access_groups.all()]
|
||||
def get_read_groups_id(self, chatmessage):
|
||||
return [group.id for group in chatmessage.chatgroup.read_groups.all()]
|
||||
|
||||
def get_write_groups_id(self, chatmessage):
|
||||
return [group.id for group in chatmessage.chatgroup.write_groups.all()]
|
||||
|
@ -51,8 +51,8 @@ class ChatGroupViewSet(ModelViewSet):
|
||||
|
||||
def update(self, *args, **kwargs):
|
||||
response = super().update(*args, **kwargs)
|
||||
# Update all affected chatmessages to update their `access_groups_id` field,
|
||||
# which is taken from the updated chatgroup.
|
||||
# Update all affected chatmessages to update their `read_groups_id` and
|
||||
# `write_groups_id` field, which is taken from the updated chatgroup.
|
||||
inform_changed_data(ChatMessage.objects.filter(chatgroup=self.get_object()))
|
||||
return response
|
||||
|
||||
@ -93,7 +93,7 @@ class ChatMessageViewSet(
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
if not serializer.validated_data["chatgroup"].can_access(self.request.user):
|
||||
if not serializer.validated_data["chatgroup"].can_write(self.request.user):
|
||||
self.permission_denied(self.request)
|
||||
|
||||
# Do not use the serializer.save since it will put the model in the history.
|
||||
|
@ -22,6 +22,7 @@ from django.http.request import QueryDict
|
||||
from django.utils.encoding import force_bytes, force_text
|
||||
from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode
|
||||
|
||||
from openslides.chat.models import ChatGroup
|
||||
from openslides.saml import SAML_ENABLED
|
||||
from openslides.utils import logging
|
||||
|
||||
@ -229,6 +230,7 @@ class UserViewSet(ModelViewSet):
|
||||
old_delegation_user.save()
|
||||
|
||||
inform_changed_data(user)
|
||||
inform_changed_data(ChatGroup.objects.all())
|
||||
return response
|
||||
|
||||
def assert_vote_not_delegated(self, user):
|
||||
|
@ -10,19 +10,24 @@ def test_motion_db_queries():
|
||||
"""
|
||||
Tests that only the following db queries for chat groups are done:
|
||||
* 1 request to get all chat groups
|
||||
* 1 request to get all access groups
|
||||
* 1 request to get all read groups
|
||||
* 1 request to get all write groups
|
||||
|
||||
Tests that only the following db queries for chat messages are done:
|
||||
* 1 request to fet all chat messages
|
||||
* 1 request to get all chat groups
|
||||
* 1 request to get all access groups
|
||||
* 1 request to get all read groups
|
||||
* 1 request to get all write groups
|
||||
"""
|
||||
group1 = get_group_model().objects.create(name="group1")
|
||||
group2 = get_group_model().objects.create(name="group2")
|
||||
group3 = get_group_model().objects.create(name="group3")
|
||||
group4 = get_group_model().objects.create(name="group4")
|
||||
|
||||
for i1 in range(5):
|
||||
chatgroup = ChatGroup.objects.create(name=f"motion{i1}")
|
||||
chatgroup.access_groups.add(group1, group2)
|
||||
chatgroup.read_groups.add(group1, group2)
|
||||
chatgroup.write_groups.add(group3, group4)
|
||||
|
||||
for i2 in range(10):
|
||||
ChatMessage.objects.create(
|
||||
@ -32,5 +37,5 @@ def test_motion_db_queries():
|
||||
chatgroup=chatgroup,
|
||||
)
|
||||
|
||||
assert count_queries(ChatGroup.get_elements)() == 2
|
||||
assert count_queries(ChatMessage.get_elements)() == 3
|
||||
assert count_queries(ChatGroup.get_elements)() == 3
|
||||
assert count_queries(ChatMessage.get_elements)() == 4
|
||||
|
Loading…
Reference in New Issue
Block a user