fix: add user popup is submittable again
react-form-hooks no longer played nice with custom input. created a third input type `FormInput` that is made to play well with the react-form-hooks. also fixes auto complete overriding bg + text color on inputs.
This commit is contained in:
parent
8b1de30204
commit
aa84cbabb2
@ -12,7 +12,7 @@ import {
|
|||||||
} from 'shared/generated/graphql';
|
} from 'shared/generated/graphql';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import Button from 'shared/components/Button';
|
import Button from 'shared/components/Button';
|
||||||
import { useForm, Controller } from 'react-hook-form';
|
import { useForm, Controller, UseFormSetError } from 'react-hook-form';
|
||||||
import { usePopup, Popup } from 'shared/components/PopupMenu';
|
import { usePopup, Popup } from 'shared/components/PopupMenu';
|
||||||
import produce from 'immer';
|
import produce from 'immer';
|
||||||
import updateApolloCache from 'shared/utils/cache';
|
import updateApolloCache from 'shared/utils/cache';
|
||||||
@ -20,6 +20,7 @@ import { useCurrentUser } from 'App/context';
|
|||||||
import { Redirect } from 'react-router';
|
import { Redirect } from 'react-router';
|
||||||
import NOOP from 'shared/utils/noop';
|
import NOOP from 'shared/utils/noop';
|
||||||
import ControlledInput from 'shared/components/ControlledInput';
|
import ControlledInput from 'shared/components/ControlledInput';
|
||||||
|
import FormInput from 'shared/components/FormInput';
|
||||||
|
|
||||||
const DeleteUserWrapper = styled.div`
|
const DeleteUserWrapper = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -77,7 +78,7 @@ const CreateUserButton = styled(Button)`
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const AddUserInput = styled(ControlledInput)`
|
const AddUserInput = styled(FormInput)`
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -87,7 +88,7 @@ const InputError = styled.span`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
type AddUserPopupProps = {
|
type AddUserPopupProps = {
|
||||||
onAddUser: (user: CreateUserData) => void;
|
onAddUser: (user: CreateUserData, setError: UseFormSetError<CreateUserData>) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const AddUserPopup: React.FC<AddUserPopupProps> = ({ onAddUser }) => {
|
const AddUserPopup: React.FC<AddUserPopupProps> = ({ onAddUser }) => {
|
||||||
@ -95,16 +96,16 @@ const AddUserPopup: React.FC<AddUserPopupProps> = ({ onAddUser }) => {
|
|||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
formState: { errors },
|
formState: { errors },
|
||||||
|
setError,
|
||||||
control,
|
control,
|
||||||
} = useForm<CreateUserData>();
|
} = useForm<CreateUserData>();
|
||||||
|
|
||||||
const createUser = (data: CreateUserData) => {
|
const createUser = (data: CreateUserData) => {
|
||||||
onAddUser(data);
|
onAddUser(data, setError);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<CreateUserForm onSubmit={handleSubmit(createUser)}>
|
<CreateUserForm onSubmit={handleSubmit(createUser)}>
|
||||||
<AddUserInput
|
<AddUserInput
|
||||||
floatingLabel
|
|
||||||
width="100%"
|
width="100%"
|
||||||
label="Full Name"
|
label="Full Name"
|
||||||
variant="alternate"
|
variant="alternate"
|
||||||
@ -118,6 +119,7 @@ const AddUserPopup: React.FC<AddUserPopupProps> = ({ onAddUser }) => {
|
|||||||
variant="alternate"
|
variant="alternate"
|
||||||
{...register('email', { required: 'Email is required' })}
|
{...register('email', { required: 'Email is required' })}
|
||||||
/>
|
/>
|
||||||
|
{errors.email && <InputError>{errors.email.message}</InputError>}
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="roleCode"
|
name="roleCode"
|
||||||
@ -241,10 +243,15 @@ TODO: add permision check
|
|||||||
$target,
|
$target,
|
||||||
<Popup tab={0} title="Add member" onClose={() => hidePopup()}>
|
<Popup tab={0} title="Add member" onClose={() => hidePopup()}>
|
||||||
<AddUserPopup
|
<AddUserPopup
|
||||||
onAddUser={(u) => {
|
onAddUser={(u, setError) => {
|
||||||
const { roleCode, ...userData } = u;
|
const { roleCode, ...userData } = u;
|
||||||
createUser({ variables: { ...userData, roleCode: roleCode.value } });
|
createUser({
|
||||||
hidePopup();
|
variables: { ...userData, roleCode: roleCode.value },
|
||||||
|
})
|
||||||
|
.then(() => hidePopup())
|
||||||
|
.catch((e) => {
|
||||||
|
setError('email', { type: 'validate', message: e.message });
|
||||||
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Popup>,
|
</Popup>,
|
||||||
|
202
frontend/src/shared/components/FormInput/index.tsx
Normal file
202
frontend/src/shared/components/FormInput/index.tsx
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
|
import styled, { css } from 'styled-components/macro';
|
||||||
|
import theme from '../../../App/ThemeStyles';
|
||||||
|
|
||||||
|
const InputWrapper = styled.div<{ width: string }>`
|
||||||
|
position: relative;
|
||||||
|
width: ${(props) => props.width};
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
margin-bottom: 2.2rem;
|
||||||
|
margin-top: 24px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const InputLabel = styled.span<{ width: string }>`
|
||||||
|
width: ${(props) => props.width};
|
||||||
|
padding: 0.7rem !important;
|
||||||
|
color: #c2c6dc;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 5px;
|
||||||
|
overflow: hidden;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
cursor: text;
|
||||||
|
font-size: 12px;
|
||||||
|
user-select: none;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const InputInput = styled.input<{
|
||||||
|
hasValue: boolean;
|
||||||
|
hasIcon: boolean;
|
||||||
|
width: string;
|
||||||
|
focusBg: string;
|
||||||
|
borderColor: string;
|
||||||
|
}>`
|
||||||
|
width: ${(props) => props.width};
|
||||||
|
font-size: 14px;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||||
|
border-color: ${(props) => props.borderColor};
|
||||||
|
background: #262c49;
|
||||||
|
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0.15);
|
||||||
|
${(props) => (props.hasIcon ? 'padding: 0.7rem 1rem 0.7rem 3rem;' : 'padding: 0.7rem;')}
|
||||||
|
|
||||||
|
&:-webkit-autofill, &:-webkit-autofill:hover, &:-webkit-autofill:focus, &:-webkit-autofill:active {
|
||||||
|
-webkit-box-shadow: 0 0 0 30px #262c49 inset !important;
|
||||||
|
}
|
||||||
|
&:-webkit-autofill {
|
||||||
|
-webkit-text-fill-color: #c2c6dc !important;
|
||||||
|
}
|
||||||
|
line-height: 16px;
|
||||||
|
color: #c2c6dc;
|
||||||
|
position: relative;
|
||||||
|
border-radius: 5px;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
&:focus {
|
||||||
|
box-shadow: 0 3px 10px 0 rgba(0, 0, 0, 0.15);
|
||||||
|
border: 1px solid ${(props) => props.theme.colors.primary};
|
||||||
|
background: ${(props) => props.focusBg};
|
||||||
|
}
|
||||||
|
&:focus ~ ${InputLabel} {
|
||||||
|
color: ${(props) => props.theme.colors.primary};
|
||||||
|
transform: translate(-3px, -90%);
|
||||||
|
}
|
||||||
|
${(props) =>
|
||||||
|
props.hasValue &&
|
||||||
|
css`
|
||||||
|
& ~ ${InputLabel} {
|
||||||
|
color: ${props.theme.colors.primary};
|
||||||
|
transform: translate(-3px, -90%);
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Icon = styled.div`
|
||||||
|
display: flex;
|
||||||
|
left: 16px;
|
||||||
|
position: absolute;
|
||||||
|
`;
|
||||||
|
|
||||||
|
type FormInputProps = {
|
||||||
|
variant?: 'normal' | 'alternate';
|
||||||
|
disabled?: boolean;
|
||||||
|
label?: string;
|
||||||
|
width?: string;
|
||||||
|
floatingLabel?: boolean;
|
||||||
|
placeholder?: string;
|
||||||
|
icon?: JSX.Element;
|
||||||
|
type?: string;
|
||||||
|
autocomplete?: boolean;
|
||||||
|
autoFocus?: boolean;
|
||||||
|
autoSelect?: boolean;
|
||||||
|
id?: string;
|
||||||
|
name?: string;
|
||||||
|
onChange: any;
|
||||||
|
onBlur: any;
|
||||||
|
className?: string;
|
||||||
|
defaultValue?: string;
|
||||||
|
value?: string;
|
||||||
|
onClick?: (e: React.MouseEvent<HTMLInputElement>) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
function useCombinedRefs(...refs: any) {
|
||||||
|
const targetRef = React.useRef();
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
refs.forEach((ref: any) => {
|
||||||
|
if (!ref) return;
|
||||||
|
|
||||||
|
if (typeof ref === 'function') {
|
||||||
|
ref(targetRef.current);
|
||||||
|
} else {
|
||||||
|
ref.current = targetRef.current;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, [refs]);
|
||||||
|
|
||||||
|
return targetRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FormInput = React.forwardRef(
|
||||||
|
(
|
||||||
|
{
|
||||||
|
disabled = false,
|
||||||
|
width = 'auto',
|
||||||
|
variant = 'normal',
|
||||||
|
type = 'text',
|
||||||
|
autoFocus = false,
|
||||||
|
autoSelect = false,
|
||||||
|
autocomplete,
|
||||||
|
label,
|
||||||
|
placeholder,
|
||||||
|
onBlur,
|
||||||
|
onChange,
|
||||||
|
icon,
|
||||||
|
name,
|
||||||
|
className,
|
||||||
|
onClick,
|
||||||
|
floatingLabel,
|
||||||
|
defaultValue,
|
||||||
|
value,
|
||||||
|
id,
|
||||||
|
}: FormInputProps,
|
||||||
|
$ref: any,
|
||||||
|
) => {
|
||||||
|
const [hasValue, setHasValue] = useState(defaultValue !== '');
|
||||||
|
const borderColor = variant === 'normal' ? 'rgba(0,0,0,0.2)' : theme.colors.alternate;
|
||||||
|
const focusBg = variant === 'normal' ? theme.colors.bg.secondary : theme.colors.bg.primary;
|
||||||
|
|
||||||
|
// Merge forwarded ref and internal ref in order to be able to access the ref in the useEffect
|
||||||
|
// The forwarded ref is not accessible by itself, which is what the innerRef & combined ref is for
|
||||||
|
// TODO(jordanknott): This is super ugly, find a better approach?
|
||||||
|
const $innerRef = React.useRef<HTMLInputElement>(null);
|
||||||
|
const combinedRef: any = useCombinedRefs($ref, $innerRef);
|
||||||
|
useEffect(() => {
|
||||||
|
if (combinedRef && combinedRef.current) {
|
||||||
|
if (autoFocus) {
|
||||||
|
combinedRef.current.focus();
|
||||||
|
}
|
||||||
|
if (autoSelect) {
|
||||||
|
combinedRef.current.select();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<InputWrapper className={className} width={width}>
|
||||||
|
<InputInput
|
||||||
|
onChange={(e) => {
|
||||||
|
setHasValue((e.currentTarget.value !== '' || floatingLabel) ?? false);
|
||||||
|
onChange(e);
|
||||||
|
}}
|
||||||
|
disabled={disabled}
|
||||||
|
hasValue={hasValue}
|
||||||
|
ref={combinedRef}
|
||||||
|
id={id}
|
||||||
|
type={type}
|
||||||
|
name={name}
|
||||||
|
onClick={onClick}
|
||||||
|
autoComplete={autocomplete ? 'on' : 'off'}
|
||||||
|
defaultValue={defaultValue}
|
||||||
|
onBlur={onBlur}
|
||||||
|
value={value}
|
||||||
|
hasIcon={typeof icon !== 'undefined'}
|
||||||
|
width={width}
|
||||||
|
placeholder={placeholder}
|
||||||
|
focusBg={focusBg}
|
||||||
|
borderColor={borderColor}
|
||||||
|
/>
|
||||||
|
{label && <InputLabel width={width}>{label}</InputLabel>}
|
||||||
|
<Icon>{icon && icon}</Icon>
|
||||||
|
</InputWrapper>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export default FormInput;
|
@ -59,6 +59,7 @@ type Querier interface {
|
|||||||
DeleteTeamMember(ctx context.Context, arg DeleteTeamMemberParams) error
|
DeleteTeamMember(ctx context.Context, arg DeleteTeamMemberParams) error
|
||||||
DeleteUserAccountByID(ctx context.Context, userID uuid.UUID) error
|
DeleteUserAccountByID(ctx context.Context, userID uuid.UUID) error
|
||||||
DeleteUserAccountInvitedForEmail(ctx context.Context, email string) error
|
DeleteUserAccountInvitedForEmail(ctx context.Context, email string) error
|
||||||
|
DoesUserExist(ctx context.Context, arg DoesUserExistParams) (bool, error)
|
||||||
GetActivityForTaskID(ctx context.Context, taskID uuid.UUID) ([]TaskActivity, error)
|
GetActivityForTaskID(ctx context.Context, taskID uuid.UUID) ([]TaskActivity, error)
|
||||||
GetAllNotificationsForUserID(ctx context.Context, notifierID uuid.UUID) ([]Notification, error)
|
GetAllNotificationsForUserID(ctx context.Context, notifierID uuid.UUID) ([]Notification, error)
|
||||||
GetAllOrganizations(ctx context.Context) ([]Organization, error)
|
GetAllOrganizations(ctx context.Context) ([]Organization, error)
|
||||||
|
@ -63,6 +63,9 @@ SELECT EXISTS(SELECT 1 FROM user_account WHERE username != 'system');
|
|||||||
-- name: HasActiveUser :one
|
-- name: HasActiveUser :one
|
||||||
SELECT EXISTS(SELECT 1 FROM user_account WHERE username != 'system' AND active = true);
|
SELECT EXISTS(SELECT 1 FROM user_account WHERE username != 'system' AND active = true);
|
||||||
|
|
||||||
|
-- name: DoesUserExist :one
|
||||||
|
SELECT EXISTS(SELECT 1 FROM user_account WHERE email = $1 OR username = $2);
|
||||||
|
|
||||||
-- name: CreateConfirmToken :one
|
-- name: CreateConfirmToken :one
|
||||||
INSERT INTO user_account_confirm_token (email) VALUES ($1) RETURNING *;
|
INSERT INTO user_account_confirm_token (email) VALUES ($1) RETURNING *;
|
||||||
|
|
||||||
|
@ -157,6 +157,22 @@ func (q *Queries) DeleteUserAccountInvitedForEmail(ctx context.Context, email st
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const doesUserExist = `-- name: DoesUserExist :one
|
||||||
|
SELECT EXISTS(SELECT 1 FROM user_account WHERE email = $1 OR username = $2)
|
||||||
|
`
|
||||||
|
|
||||||
|
type DoesUserExistParams struct {
|
||||||
|
Email string `json:"email"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) DoesUserExist(ctx context.Context, arg DoesUserExistParams) (bool, error) {
|
||||||
|
row := q.db.QueryRowContext(ctx, doesUserExist, arg.Email, arg.Username)
|
||||||
|
var exists bool
|
||||||
|
err := row.Scan(&exists)
|
||||||
|
return exists, err
|
||||||
|
}
|
||||||
|
|
||||||
const getAllUserAccounts = `-- name: GetAllUserAccounts :many
|
const getAllUserAccounts = `-- name: GetAllUserAccounts :many
|
||||||
SELECT user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code, bio, active FROM user_account WHERE username != 'system'
|
SELECT user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code, bio, active FROM user_account WHERE username != 'system'
|
||||||
`
|
`
|
||||||
|
@ -872,22 +872,26 @@ func (r *mutationResolver) DeleteTeam(ctx context.Context, input DeleteTeam) (*D
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *mutationResolver) CreateTeam(ctx context.Context, input NewTeam) (*db.Team, error) {
|
func (r *mutationResolver) CreateTeam(ctx context.Context, input NewTeam) (*db.Team, error) {
|
||||||
_, ok := GetUser(ctx)
|
userID, ok := GetUserID(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return &db.Team{}, nil
|
return &db.Team{}, nil
|
||||||
}
|
}
|
||||||
// if role == auth.RoleAdmin { // TODO: add permision check
|
role, err := r.Repository.GetRoleForUserID(ctx, userID)
|
||||||
if true {
|
if err != nil {
|
||||||
createdAt := time.Now().UTC()
|
log.WithError(err).Error("while creating team")
|
||||||
team, err := r.Repository.CreateTeam(ctx, db.CreateTeamParams{OrganizationID: input.OrganizationID, CreatedAt: createdAt, Name: input.Name})
|
return &db.Team{}, nil
|
||||||
return &team, err
|
|
||||||
}
|
}
|
||||||
return &db.Team{}, &gqlerror.Error{
|
if ConvertToRoleCode(role.Code) != RoleCodeAdmin {
|
||||||
Message: "You must be an organization admin to create new teams",
|
return &db.Team{}, &gqlerror.Error{
|
||||||
Extensions: map[string]interface{}{
|
Message: "Must be an organization admin",
|
||||||
"code": "1-400",
|
Extensions: map[string]interface{}{
|
||||||
},
|
"code": "0-400",
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
createdAt := time.Now().UTC()
|
||||||
|
team, err := r.Repository.CreateTeam(ctx, db.CreateTeamParams{OrganizationID: input.OrganizationID, CreatedAt: createdAt, Name: input.Name})
|
||||||
|
return &team, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *mutationResolver) CreateTeamMember(ctx context.Context, input CreateTeamMember) (*CreateTeamMemberPayload, error) {
|
func (r *mutationResolver) CreateTeamMember(ctx context.Context, input CreateTeamMember) (*CreateTeamMemberPayload, error) {
|
||||||
@ -954,12 +958,16 @@ func (r *mutationResolver) DeleteTeamMember(ctx context.Context, input DeleteTea
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *mutationResolver) CreateUserAccount(ctx context.Context, input NewUserAccount) (*db.UserAccount, error) {
|
func (r *mutationResolver) CreateUserAccount(ctx context.Context, input NewUserAccount) (*db.UserAccount, error) {
|
||||||
_, ok := GetUser(ctx)
|
userID, ok := GetUserID(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return &db.UserAccount{}, nil
|
return &db.UserAccount{}, nil
|
||||||
}
|
}
|
||||||
// if role != auth.RoleAdmin { TODO: add permsion check
|
role, err := r.Repository.GetRoleForUserID(ctx, userID)
|
||||||
if true {
|
if err != nil {
|
||||||
|
log.WithError(err).Error("while creating user account")
|
||||||
|
return &db.UserAccount{}, nil
|
||||||
|
}
|
||||||
|
if ConvertToRoleCode(role.Code) != RoleCodeAdmin {
|
||||||
return &db.UserAccount{}, &gqlerror.Error{
|
return &db.UserAccount{}, &gqlerror.Error{
|
||||||
Message: "Must be an organization admin",
|
Message: "Must be an organization admin",
|
||||||
Extensions: map[string]interface{}{
|
Extensions: map[string]interface{}{
|
||||||
@ -972,6 +980,19 @@ func (r *mutationResolver) CreateUserAccount(ctx context.Context, input NewUserA
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return &db.UserAccount{}, err
|
return &db.UserAccount{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
userExists, err := r.Repository.DoesUserExist(ctx, db.DoesUserExistParams{Username: input.Username, Email: input.Email})
|
||||||
|
if err != nil {
|
||||||
|
return &db.UserAccount{}, err
|
||||||
|
}
|
||||||
|
if userExists {
|
||||||
|
return &db.UserAccount{}, &gqlerror.Error{
|
||||||
|
Message: "User with that username or email already exists",
|
||||||
|
Extensions: map[string]interface{}{
|
||||||
|
"code": "0-300",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
userAccount, err := r.Repository.CreateUserAccount(ctx, db.CreateUserAccountParams{
|
userAccount, err := r.Repository.CreateUserAccount(ctx, db.CreateUserAccountParams{
|
||||||
FullName: input.FullName,
|
FullName: input.FullName,
|
||||||
RoleCode: input.RoleCode,
|
RoleCode: input.RoleCode,
|
||||||
@ -986,16 +1007,20 @@ func (r *mutationResolver) CreateUserAccount(ctx context.Context, input NewUserA
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *mutationResolver) DeleteUserAccount(ctx context.Context, input DeleteUserAccount) (*DeleteUserAccountPayload, error) {
|
func (r *mutationResolver) DeleteUserAccount(ctx context.Context, input DeleteUserAccount) (*DeleteUserAccountPayload, error) {
|
||||||
_, ok := GetUser(ctx)
|
userID, ok := GetUserID(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return &DeleteUserAccountPayload{Ok: false}, nil
|
return &DeleteUserAccountPayload{Ok: false}, nil
|
||||||
}
|
}
|
||||||
// if role != auth.RoleAdmin { TODO: add permision check
|
role, err := r.Repository.GetRoleForUserID(ctx, userID)
|
||||||
if true {
|
if err != nil {
|
||||||
return &DeleteUserAccountPayload{Ok: false}, &gqlerror.Error{
|
log.WithError(err).Error("while deleting user account")
|
||||||
Message: "User not found",
|
return &DeleteUserAccountPayload{}, nil
|
||||||
|
}
|
||||||
|
if ConvertToRoleCode(role.Code) != RoleCodeAdmin {
|
||||||
|
return &DeleteUserAccountPayload{}, &gqlerror.Error{
|
||||||
|
Message: "Must be an organization admin",
|
||||||
Extensions: map[string]interface{}{
|
Extensions: map[string]interface{}{
|
||||||
"code": "0-401",
|
"code": "0-400",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1004,8 +1029,6 @@ func (r *mutationResolver) DeleteUserAccount(ctx context.Context, input DeleteUs
|
|||||||
return &DeleteUserAccountPayload{Ok: false}, err
|
return &DeleteUserAccountPayload{Ok: false}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(jordanknott) migrate admin ownership
|
|
||||||
|
|
||||||
err = r.Repository.DeleteUserAccountByID(ctx, input.UserID)
|
err = r.Repository.DeleteUserAccountByID(ctx, input.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &DeleteUserAccountPayload{Ok: false}, err
|
return &DeleteUserAccountPayload{Ok: false}, err
|
||||||
@ -1062,16 +1085,20 @@ func (r *mutationResolver) UpdateUserPassword(ctx context.Context, input UpdateU
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *mutationResolver) UpdateUserRole(ctx context.Context, input UpdateUserRole) (*UpdateUserRolePayload, error) {
|
func (r *mutationResolver) UpdateUserRole(ctx context.Context, input UpdateUserRole) (*UpdateUserRolePayload, error) {
|
||||||
_, ok := GetUser(ctx)
|
userID, ok := GetUserID(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return &UpdateUserRolePayload{}, nil
|
return &UpdateUserRolePayload{}, nil
|
||||||
}
|
}
|
||||||
// if role != auth.RoleAdmin { TODO: add permision check
|
role, err := r.Repository.GetRoleForUserID(ctx, userID)
|
||||||
if true {
|
if err != nil {
|
||||||
|
log.WithError(err).Error("while updating user role")
|
||||||
|
return &UpdateUserRolePayload{}, nil
|
||||||
|
}
|
||||||
|
if ConvertToRoleCode(role.Code) != RoleCodeAdmin {
|
||||||
return &UpdateUserRolePayload{}, &gqlerror.Error{
|
return &UpdateUserRolePayload{}, &gqlerror.Error{
|
||||||
Message: "User not found",
|
Message: "Must be an organization admin",
|
||||||
Extensions: map[string]interface{}{
|
Extensions: map[string]interface{}{
|
||||||
"code": "0-401",
|
"code": "0-400",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1331,14 +1358,7 @@ func (r *queryResolver) Projects(ctx context.Context, input *ProjectsFilter) ([]
|
|||||||
|
|
||||||
var teams []db.Team
|
var teams []db.Team
|
||||||
var err error
|
var err error
|
||||||
/* TODO: add permsion check
|
teams, err = r.Repository.GetTeamsForUserIDWhereAdmin(ctx, userID)
|
||||||
if orgRole == "admin" {
|
|
||||||
teams, err = r.Repository.GetAllTeams(ctx)
|
|
||||||
} else {
|
|
||||||
teams, err = r.Repository.GetTeamsForUserIDWhereAdmin(ctx, userID)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
teams, err = r.Repository.GetAllTeams(ctx)
|
|
||||||
|
|
||||||
projects := make(map[string]db.Project)
|
projects := make(map[string]db.Project)
|
||||||
for _, team := range teams {
|
for _, team := range teams {
|
||||||
@ -1390,13 +1410,6 @@ func (r *queryResolver) Teams(ctx context.Context) ([]db.Team, error) {
|
|||||||
return []db.Team{}, errors.New("internal error")
|
return []db.Team{}, errors.New("internal error")
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
TODO: add permision check
|
|
||||||
if orgRole == "admin" {
|
|
||||||
return r.Repository.GetAllTeams(ctx)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
teams := make(map[string]db.Team)
|
teams := make(map[string]db.Team)
|
||||||
adminTeams, err := r.Repository.GetTeamsForUserIDWhereAdmin(ctx, userID)
|
adminTeams, err := r.Repository.GetTeamsForUserIDWhereAdmin(ctx, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user