Skip to content

Commit

Permalink
fix: Invited member can't access team projects (#433)
Browse files Browse the repository at this point in the history
  • Loading branch information
HugoRCD authored Jan 21, 2025
1 parent 00f01a3 commit 73be6fb
Show file tree
Hide file tree
Showing 18 changed files with 599 additions and 544 deletions.
4 changes: 0 additions & 4 deletions apps/lp/.config/shelve.config.json

This file was deleted.

2 changes: 1 addition & 1 deletion apps/lp/app/pages/[...slug].vue
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ const communityLinks = computed(() => [
</UPageBody>

<template v-if="page?.body?.toc?.links?.length" #right>
<UContentToc :links="page.body.toc.links" class="z-[2] bg-white dark:bg-neutral-950">
<UContentToc highlight :links="page.body.toc.links" class="z-[2] bg-white dark:bg-neutral-950">
<template #default>
<div class="flex items-center gap-2">
<UIcon name="i-lucide-align-left" />
Expand Down
4 changes: 0 additions & 4 deletions apps/shelve/.config/shelve.config.json

This file was deleted.

4 changes: 3 additions & 1 deletion apps/shelve/app/components/project/MainSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,12 @@ const items = [
a.click()
}
},
],
[
{
label: 'Delete project',
icon: 'lucide:trash',
iconClass: 'text-red-500 dark:text-red-500',
color: 'error',
disabled: teamRole.value !== TeamRole.OWNER,
onSelect: () => showDelete.value = !showDelete.value
}
Expand Down
3 changes: 2 additions & 1 deletion apps/shelve/app/components/team/AddMember.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script setup lang="ts">
import { type Member, Role, TeamRole } from '@shelve/types'
import { cleanString } from '~~/server/utils/string'
type TeamMemberProps = { members: Member[] }
Expand Down Expand Up @@ -38,7 +39,7 @@ const loadingMembers = ref(false)
function addMemberFunction(email: string, role: TeamRole) {
loadingMembers.value = true
toast.promise(addMember(email, role), {
toast.promise(addMember(cleanString(email), role), {
loading: 'Adding member...',
success: 'Member added successfully',
error: 'Error adding member',
Expand Down
13 changes: 8 additions & 5 deletions apps/shelve/app/components/variable/Item.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
<script setup lang="ts">
import { type Environment, type Variable } from '@shelve/types'
import { type Environment, TeamRole, type Variable } from '@shelve/types'
const { variable, environments } = defineProps<{
variable: Variable
environments: Environment[]
isSelected: boolean
}>()
const teamRole = useTeamRole() //TODO handle roles
const teamRole = useTeamRole()
const canDelete = computed(() => hasAccess(teamRole.value, TeamRole.OWNER))
const canUpdate = computed(() => hasAccess(teamRole.value, TeamRole.ADMIN))
const {
updateLoading,
Expand Down Expand Up @@ -121,18 +123,19 @@ const showEdit = ref(false)
</div>
<div class="flex justify-between gap-4">
<UButton
v-if="canDelete"
color="error"
variant="ghost"
:loading="deleteLoading"
@click="deleteVariable(variable.id)"
>
Delete
</UButton>
<div class="flex gap-2">
<div class="flex justify-end w-full gap-2">
<UButton variant="soft" @click="showEdit = false">
Cancel
Close
</UButton>
<UButton type="submit" trailing :loading="updateLoading" trailing-icon="lucide:save">
<UButton v-if="canUpdate" type="submit" trailing :loading="updateLoading" trailing-icon="lucide:save">
Save
</UButton>
</div>
Expand Down
2 changes: 1 addition & 1 deletion apps/shelve/app/pages/[teamSlug]/members.vue
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ const items = (row: Member) => [
{
label: 'Delete',
icon: 'heroicons:trash-20-solid',
iconClass: 'text-red-500 dark:text-red-500',
color: 'error',
disabled: !canDelete.value,
onSelect: () => {
if (row.role === TeamRole.OWNER) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script setup lang="ts">
import { TeamRole } from '@shelve/types'
import { useCurrentLoading } from '~/composables/useProjects'
import type { FormSubmitEvent } from '#ui/types'
import { type UpdateProjectSchema, updateProjectSchema } from '~/utils/zod/project'
Expand All @@ -9,6 +10,9 @@ const project = useProject(projectId)
const currentLoading = useCurrentLoading()
const teamRole = useTeamRole()
const canUpdate = computed(() => hasAccess(teamRole.value, TeamRole.ADMIN))
async function onSubmit(event: FormSubmitEvent<UpdateProjectSchema>) {
await useProjectsService().updateProject(event.data)
}
Expand Down Expand Up @@ -50,21 +54,21 @@ async function onSubmit(event: FormSubmitEvent<UpdateProjectSchema>) {
:ui="{ help: 'text-xs' }"
>
<div class="flex items-center gap-1">
<UInput v-model="project.repository" class="md:w-2/3" />
<UInput v-model="project.repository" class="md:w-2/3" :disabled="!canUpdate" />
<ProjectRepoSelector v-model="project.repository" />
</div>
</UFormField>
</div>
<div>
<USkeleton v-if="currentLoading" class="h-8" />
<UFormField v-else name="projectManager" label="Project Manager">
<UInput v-model="project.projectManager" class="md:w-2/3" />
<UInput v-model="project.projectManager" class="md:w-2/3" :disabled="!canUpdate" />
</UFormField>
</div>
<div>
<USkeleton v-if="currentLoading" class="h-8" />
<UFormField v-else name="homepage" label="Homepage">
<UInput v-model="project.homepage" class="md:w-2/3" />
<UInput v-model="project.homepage" class="md:w-2/3" :disabled="!canUpdate" />
</UFormField>
</div>
</div>
Expand All @@ -82,7 +86,9 @@ async function onSubmit(event: FormSubmitEvent<UpdateProjectSchema>) {
<div class="my-2 flex flex-col gap-4">
<div>
<USkeleton v-if="currentLoading" class="h-8" />
<FormGroup v-else v-model="project.variablePrefix" type="textarea" label="Prefix" class="md:w-2/3" />
<UFormField v-else v-model="project.variablePrefix" label="Prefix" class="md:w-2/3">
<UTextarea v-model="project.variablePrefix" class="w-full" :disabled="!canUpdate" :rows="4" />
</UFormField>
<UTooltip text="Yes this will be improved in the future 😅">
<p class="mt-1 text-xs text-neutral-500 dark:text-neutral-400">
Write your prefix separated by a comma, for example: <code>NUXT_PUBLIC_, REACT_APP_</code>
Expand All @@ -92,7 +98,7 @@ async function onSubmit(event: FormSubmitEvent<UpdateProjectSchema>) {
</div>
</div>
</div>
<template #footer>
<template v-if="canUpdate" #footer>
<div class="flex justify-end gap-4">
<UButton type="submit" trailing loading-auto>
Save
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import type { Variable } from '@shelve/types'
import { TeamRole, type Variable } from '@shelve/types'
const route = useRoute()
const projectId = route.params.projectId as string
Expand Down
2 changes: 1 addition & 1 deletion apps/shelve/app/pages/admin/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ const items = (row: User) => [
{
label: 'Delete',
icon: 'heroicons:trash-20-solid',
iconClass: 'text-red-500 dark:text-red-500',
color: 'error',
onSelect: () => {
if (row.role === Role.ADMIN) {
toast.error('Cannot delete admin')
Expand Down
1 change: 1 addition & 0 deletions apps/shelve/server/api/teams/[slug]/members/[id].delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export default eventHandler(async (event) => {

await new MembersService().removeMember({
teamId: team.id,
slug: team.slug,
memberId: id,
})

Expand Down
1 change: 1 addition & 0 deletions apps/shelve/server/api/teams/[slug]/members/[id].put.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export default eventHandler(async (event) => {

return new MembersService().updateMember({
teamId: team.id,
slug: team.slug,
memberId: id,
role
})
Expand Down
1 change: 1 addition & 0 deletions apps/shelve/server/api/teams/[slug]/members/index.post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default eventHandler(async (event) => {

return await new MembersService().addMember({
teamId: team.id,
slug: team.slug, // use for caching
email,
role
})
Expand Down
13 changes: 7 additions & 6 deletions apps/shelve/server/services/members.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import type { AddMemberInput, Member, RemoveMemberInput, UpdateMemberInput, User
export class MembersService {

async addMember(input: AddMemberInput): Promise<Member> {
const { teamId, email, role } = input
const { teamId, email, role, slug } = input
const foundedMember = await this.isUserAlreadyMember(teamId, email)
if (foundedMember) {
return await this.updateMember({
teamId,
slug,
memberId: foundedMember.id,
role
})
Expand All @@ -23,12 +24,12 @@ export class MembersService {
.returning()
if (!newMember) throw createError({ statusCode: 422, message: 'Failed to add member' })
const member = await this.findMemberById(newMember.id)
await clearCache('Team', teamId)
await clearCache('Team', slug)
return member
}

async updateMember(input: UpdateMemberInput): Promise<Member> {
const { teamId, memberId, role } = input
const { slug, memberId, role } = input

await useDrizzle().update(tables.members)
.set({
Expand All @@ -37,15 +38,15 @@ export class MembersService {
.where(eq(tables.members.id, memberId))

const member = await this.findMemberById(memberId)
await clearCache('Team', teamId)
await clearCache('Team', slug)
return member
}

async removeMember(input: RemoveMemberInput): Promise<void> {
const { teamId, memberId } = input
const { memberId, slug } = input

const member = await this.findMemberById(memberId)
await clearCache('Team', teamId)
await clearCache('Team', slug)
await useDrizzle().delete(tables.members).where(eq(tables.members.id, member.id))
}

Expand Down
6 changes: 6 additions & 0 deletions apps/shelve/server/utils/string.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const cleanString = (str: string) => {
return str
.replace(/[\t\r\n]/g, '') // Remove tabs, line breaks
.replace(/\s+/g, ' ') // Replace multiple spaces with a single space
.trim()
}
2 changes: 1 addition & 1 deletion packages/types/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@shelve/types",
"version": "1.7.2",
"version": "1.7.3",
"type": "module",
"publishConfig": {
"access": "public"
Expand Down
3 changes: 3 additions & 0 deletions packages/types/src/Team.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,20 @@ export type DeleteTeamInput = {

export type AddMemberInput = {
teamId: number;
slug: string;
email: string;
role: TeamRole;
}

export type UpdateMemberInput = {
teamId: number;
slug: string;
memberId: number;
role: TeamRole;
}

export type RemoveMemberInput = {
teamId: number;
slug: string;
memberId: number;
}
Loading

0 comments on commit 73be6fb

Please sign in to comment.