Compare commits
1 Commits
fix/duplic
...
fix/unifie
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4276fc0adf |
@@ -236,11 +236,11 @@ export class AdminService {
|
||||
const user = await this.userService.findUserByEmail(userEmail);
|
||||
if (O.isNone(user)) return E.left(USER_NOT_FOUND);
|
||||
|
||||
const teamMember = await this.teamService.getTeamMemberTE(
|
||||
const isUserAlreadyMember = await this.teamService.getTeamMemberTE(
|
||||
teamID,
|
||||
user.value.uid,
|
||||
)();
|
||||
if (E.isLeft(teamMember)) {
|
||||
if (E.left(isUserAlreadyMember)) {
|
||||
const addedUser = await this.teamService.addMemberToTeamWithEmail(
|
||||
teamID,
|
||||
userEmail,
|
||||
@@ -248,18 +248,6 @@ export class AdminService {
|
||||
);
|
||||
if (E.isLeft(addedUser)) return E.left(addedUser.left);
|
||||
|
||||
const userInvitation =
|
||||
await this.teamInvitationService.getTeamInviteByEmailAndTeamID(
|
||||
userEmail,
|
||||
teamID,
|
||||
);
|
||||
|
||||
if (E.isRight(userInvitation)) {
|
||||
await this.teamInvitationService.revokeInvitation(
|
||||
userInvitation.right.id,
|
||||
)();
|
||||
}
|
||||
|
||||
return E.right(addedUser.right);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ import * as T from 'fp-ts/Task';
|
||||
import * as O from 'fp-ts/Option';
|
||||
import * as TO from 'fp-ts/TaskOption';
|
||||
import * as TE from 'fp-ts/TaskEither';
|
||||
import * as E from 'fp-ts/Either';
|
||||
import { pipe, flow, constVoid } from 'fp-ts/function';
|
||||
import { PrismaService } from 'src/prisma/prisma.service';
|
||||
import { Team, TeamMemberRole } from 'src/team/team.model';
|
||||
@@ -11,7 +10,6 @@ import { Email } from 'src/types/Email';
|
||||
import { User } from 'src/user/user.model';
|
||||
import { TeamService } from 'src/team/team.service';
|
||||
import {
|
||||
INVALID_EMAIL,
|
||||
TEAM_INVITE_ALREADY_MEMBER,
|
||||
TEAM_INVITE_EMAIL_DO_NOT_MATCH,
|
||||
TEAM_INVITE_MEMBER_HAS_INVITE,
|
||||
@@ -21,7 +19,6 @@ import { TeamInvitation } from './team-invitation.model';
|
||||
import { MailerService } from 'src/mailer/mailer.service';
|
||||
import { UserService } from 'src/user/user.service';
|
||||
import { PubSubService } from 'src/pubsub/pubsub.service';
|
||||
import { validateEmail } from '../utils';
|
||||
|
||||
@Injectable()
|
||||
export class TeamInvitationService {
|
||||
@@ -66,32 +63,6 @@ export class TeamInvitationService {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the team invite for an invitee with email and teamID.
|
||||
* @param inviteeEmail invitee email
|
||||
* @param teamID team id
|
||||
* @returns an Either of team invitation for the invitee or error
|
||||
*/
|
||||
async getTeamInviteByEmailAndTeamID(inviteeEmail: string, teamID: string) {
|
||||
const isEmailValid = validateEmail(inviteeEmail);
|
||||
if (!isEmailValid) return E.left(INVALID_EMAIL);
|
||||
|
||||
try {
|
||||
const teamInvite = await this.prisma.teamInvitation.findUniqueOrThrow({
|
||||
where: {
|
||||
teamID_inviteeEmail: {
|
||||
inviteeEmail: inviteeEmail,
|
||||
teamID: teamID,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return E.right(teamInvite);
|
||||
} catch (e) {
|
||||
return E.left(TEAM_INVITE_NO_INVITE_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
createInvitation(
|
||||
creator: User,
|
||||
team: Team,
|
||||
|
||||
@@ -86,7 +86,6 @@ declare module '@vue/runtime-core' {
|
||||
HoppSmartLink: typeof import('@hoppscotch/ui')['HoppSmartLink']
|
||||
HoppSmartModal: typeof import('@hoppscotch/ui')['HoppSmartModal']
|
||||
HoppSmartPicture: typeof import('@hoppscotch/ui')['HoppSmartPicture']
|
||||
HoppSmartPlaceholder: typeof import('@hoppscotch/ui')['HoppSmartPlaceholder']
|
||||
HoppSmartProgressRing: typeof import('@hoppscotch/ui')['HoppSmartProgressRing']
|
||||
HoppSmartRadioGroup: typeof import('@hoppscotch/ui')['HoppSmartRadioGroup']
|
||||
HoppSmartSlideOver: typeof import('@hoppscotch/ui')['HoppSmartSlideOver']
|
||||
|
||||
@@ -142,14 +142,12 @@
|
||||
<div v-if="authType === 'basic'">
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
:environmentHighlights="false"
|
||||
v-model="basicUsername"
|
||||
:placeholder="t('authorization.username')"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
:environmentHighlights="false"
|
||||
v-model="basicPassword"
|
||||
:placeholder="t('authorization.password')"
|
||||
/>
|
||||
@@ -157,37 +155,21 @@
|
||||
</div>
|
||||
<div v-if="authType === 'bearer'">
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
:environmentHighlights="false"
|
||||
v-model="bearerToken"
|
||||
placeholder="Token"
|
||||
/>
|
||||
<SmartEnvInput v-model="bearerToken" placeholder="Token" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="authType === 'oauth-2'">
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
:environmentHighlights="false"
|
||||
v-model="oauth2Token"
|
||||
placeholder="Token"
|
||||
/>
|
||||
<SmartEnvInput v-model="oauth2Token" placeholder="Token" />
|
||||
</div>
|
||||
<HttpOAuth2Authorization />
|
||||
</div>
|
||||
<div v-if="authType === 'api-key'">
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
:environmentHighlights="false"
|
||||
v-model="apiKey"
|
||||
placeholder="Key"
|
||||
/>
|
||||
<SmartEnvInput v-model="apiKey" placeholder="Key" />
|
||||
</div>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
:environmentHighlights="false"
|
||||
v-model="apiValue"
|
||||
placeholder="Value"
|
||||
/>
|
||||
<SmartEnvInput v-model="apiValue" placeholder="Value" />
|
||||
</div>
|
||||
<div class="flex items-center border-b border-dividerLight">
|
||||
<span class="flex items-center">
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
<HoppButtonPrimary
|
||||
id="get"
|
||||
name="get"
|
||||
:loading="isLoading"
|
||||
:label="!connected ? t('action.connect') : t('action.disconnect')"
|
||||
class="w-32"
|
||||
@click="onConnectClick"
|
||||
@@ -32,12 +31,7 @@ import { GQLConnection } from "~/helpers/GQLConnection"
|
||||
import { getCurrentStrategyID } from "~/helpers/network"
|
||||
import { useReadonlyStream, useStream } from "@composables/stream"
|
||||
import { useI18n } from "@composables/i18n"
|
||||
import {
|
||||
gqlAuth$,
|
||||
gqlHeaders$,
|
||||
gqlURL$,
|
||||
setGQLURL,
|
||||
} from "~/newstore/GQLSession"
|
||||
import { gqlHeaders$, gqlURL$, setGQLURL } from "~/newstore/GQLSession"
|
||||
|
||||
const t = useI18n()
|
||||
|
||||
@@ -46,18 +40,13 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const connected = useReadonlyStream(props.conn.connected$, false)
|
||||
const isLoading = useReadonlyStream(props.conn.isLoading$, false)
|
||||
const headers = useReadonlyStream(gqlHeaders$, [])
|
||||
const auth = useReadonlyStream(gqlAuth$, {
|
||||
authType: "none",
|
||||
authActive: true,
|
||||
})
|
||||
|
||||
const url = useStream(gqlURL$, "", setGQLURL)
|
||||
|
||||
const onConnectClick = () => {
|
||||
if (!connected.value) {
|
||||
props.conn.connect(url.value, headers.value as any, auth.value)
|
||||
props.conn.connect(url.value, headers.value as any)
|
||||
|
||||
platform.analytics?.logHoppRequestRunToAnalytics({
|
||||
platform: "graphql-schema",
|
||||
|
||||
@@ -44,7 +44,6 @@ const props = withDefaults(
|
||||
envs?: { key: string; value: string; source: string }[] | null
|
||||
focus?: boolean
|
||||
selectTextOnMount?: boolean
|
||||
environmentHighlights?: boolean
|
||||
readonly?: boolean
|
||||
}>(),
|
||||
{
|
||||
@@ -54,7 +53,6 @@ const props = withDefaults(
|
||||
envs: null,
|
||||
focus: false,
|
||||
readonly: false,
|
||||
environmentHighlights: true,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -144,7 +142,7 @@ const initView = (el: any) => {
|
||||
tooltips({
|
||||
position: "absolute",
|
||||
}),
|
||||
props.environmentHighlights ? envTooltipPlugin : [],
|
||||
envTooltipPlugin,
|
||||
placeholderExt(props.placeholder),
|
||||
EditorView.domEventHandlers({
|
||||
paste(ev) {
|
||||
|
||||
@@ -99,7 +99,7 @@ export class GQLConnection {
|
||||
|
||||
private timeoutSubscription: any
|
||||
|
||||
public connect(url: string, headers: GQLHeader[], auth: HoppGQLAuth) {
|
||||
public connect(url: string, headers: GQLHeader[]) {
|
||||
if (this.connected$.value) {
|
||||
throw new Error(
|
||||
"A connection is already running. Close it before starting another."
|
||||
@@ -110,7 +110,7 @@ export class GQLConnection {
|
||||
this.connected$.next(true)
|
||||
|
||||
const poll = async () => {
|
||||
await this.getSchema(url, headers, auth)
|
||||
await this.getSchema(url, headers)
|
||||
this.timeoutSubscription = setTimeout(() => {
|
||||
poll()
|
||||
}, GQL_SCHEMA_POLL_INTERVAL)
|
||||
@@ -135,11 +135,7 @@ export class GQLConnection {
|
||||
this.schema$.next(null)
|
||||
}
|
||||
|
||||
private async getSchema(
|
||||
url: string,
|
||||
reqHeaders: GQLHeader[],
|
||||
auth: HoppGQLAuth
|
||||
) {
|
||||
private async getSchema(url: string, headers: GQLHeader[]) {
|
||||
try {
|
||||
this.isLoading$.next(true)
|
||||
|
||||
@@ -147,38 +143,10 @@ export class GQLConnection {
|
||||
query: getIntrospectionQuery(),
|
||||
})
|
||||
|
||||
const headers = reqHeaders.filter((x) => x.active && x.key !== "")
|
||||
|
||||
// TODO: Support a better b64 implementation than btoa ?
|
||||
if (auth.authType === "basic") {
|
||||
const username = auth.username
|
||||
const password = auth.password
|
||||
|
||||
headers.push({
|
||||
active: true,
|
||||
key: "Authorization",
|
||||
value: `Basic ${btoa(`${username}:${password}`)}`,
|
||||
})
|
||||
} else if (auth.authType === "bearer" || auth.authType === "oauth-2") {
|
||||
headers.push({
|
||||
active: true,
|
||||
key: "Authorization",
|
||||
value: `Bearer ${auth.token}`,
|
||||
})
|
||||
} else if (auth.authType === "api-key") {
|
||||
const { key, value, addTo } = auth
|
||||
|
||||
if (addTo === "Headers") {
|
||||
headers.push({
|
||||
active: true,
|
||||
key,
|
||||
value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const finalHeaders: Record<string, string> = {}
|
||||
headers.forEach((x) => (finalHeaders[x.key] = x.value))
|
||||
headers
|
||||
.filter((x) => x.active && x.key !== "")
|
||||
.forEach((x) => (finalHeaders[x.key] = x.value))
|
||||
|
||||
const reqOptions = {
|
||||
method: "POST",
|
||||
|
||||
@@ -275,4 +275,7 @@ export const gqlResponse$ = gqlSessionStore.subject$.pipe(
|
||||
distinctUntilChanged()
|
||||
)
|
||||
|
||||
export const gqlAuth$ = gqlSessionStore.subject$.pipe(pluck("request", "auth"))
|
||||
export const gqlAuth$ = gqlSessionStore.subject$.pipe(
|
||||
pluck("request", "auth"),
|
||||
distinctUntilChanged()
|
||||
)
|
||||
|
||||
@@ -47,8 +47,6 @@ import {
|
||||
loadTabsFromPersistedState,
|
||||
persistableTabState,
|
||||
} from "~/helpers/rest/tab"
|
||||
import { debounceTime } from "rxjs"
|
||||
import { gqlSessionStore, setGQLSession } from "./GQLSession"
|
||||
|
||||
function checkAndMigrateOldSettings() {
|
||||
if (window.localStorage.getItem("selectedEnvIndex")) {
|
||||
@@ -335,35 +333,12 @@ export function setupRESTTabsPersistence() {
|
||||
)
|
||||
}
|
||||
|
||||
// temporary persistence for GQL session
|
||||
export function setupGQLPersistence() {
|
||||
try {
|
||||
const state = window.localStorage.getItem("gqlState")
|
||||
if (state) {
|
||||
const data = JSON.parse(state)
|
||||
data["schema"] = ""
|
||||
data["response"] = ""
|
||||
setGQLSession(data)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(
|
||||
`Failed parsing persisted GraphQL state, state:`,
|
||||
window.localStorage.getItem("gqlState")
|
||||
)
|
||||
}
|
||||
|
||||
gqlSessionStore.subject$.pipe(debounceTime(500)).subscribe((state) => {
|
||||
window.localStorage.setItem("gqlState", JSON.stringify(state))
|
||||
})
|
||||
}
|
||||
|
||||
export function setupLocalPersistence() {
|
||||
checkAndMigrateOldSettings()
|
||||
|
||||
setupLocalStatePersistence()
|
||||
setupSettingsPersistence()
|
||||
setupRESTTabsPersistence()
|
||||
setupGQLPersistence()
|
||||
setupHistoryPersistence()
|
||||
setupCollectionsPersistence()
|
||||
setupGlobalEnvsPersistence()
|
||||
|
||||
@@ -14,10 +14,12 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { usePageHead } from "@composables/head"
|
||||
import { computed, onBeforeUnmount, watch } from "vue"
|
||||
import { useReadonlyStream } from "@composables/stream"
|
||||
import { useI18n } from "@composables/i18n"
|
||||
import { usePageHead } from "@composables/head"
|
||||
import { startPageProgress, completePageProgress } from "@modules/loadingbar"
|
||||
import { GQLConnection } from "@helpers/GQLConnection"
|
||||
import { computed, onBeforeUnmount } from "vue"
|
||||
|
||||
const t = useI18n()
|
||||
|
||||
@@ -26,10 +28,16 @@ usePageHead({
|
||||
})
|
||||
|
||||
const gqlConn = new GQLConnection()
|
||||
const isLoading = useReadonlyStream(gqlConn.isLoading$, false)
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (gqlConn.connected$.value) {
|
||||
gqlConn.disconnect()
|
||||
}
|
||||
})
|
||||
|
||||
watch(isLoading, () => {
|
||||
if (isLoading.value) startPageProgress()
|
||||
else completePageProgress()
|
||||
})
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user