Subdomain li Tenant sistemi ve Profil resim problemi

This commit is contained in:
Sedat ÖZTÜRK 2025-06-24 16:21:19 +03:00
parent 4252cbf0f5
commit 10493bd067
12 changed files with 108 additions and 74 deletions

View file

@ -37,6 +37,19 @@ public class PlatformTenantAppService : TenantAppService, IPlatformTenantAppServ
LocalizationResource = typeof(PlatformResource); LocalizationResource = typeof(PlatformResource);
} }
public override Task<TenantDto> GetAsync(Guid id)
{
return base.GetAsync(id);
}
[AllowAnonymous]
public async Task<TenantDto> GetByNameAsync(string name)
{
return ObjectMapper.Map<Tenant, TenantDto>(
await TenantRepository.FindByNameAsync(name)
);
}
[AllowAnonymous] [AllowAnonymous]
public override Task<PagedResultDto<TenantDto>> GetListAsync(GetTenantsInput input) => base.GetListAsync(input); public override Task<PagedResultDto<TenantDto>> GetListAsync(GetTenantsInput input) => base.GetListAsync(input);

View file

@ -6754,7 +6754,7 @@
"ParentName": null, "ParentName": null,
"DisplayName": "App.ForumManagement", "DisplayName": "App.ForumManagement",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3 "MultiTenancySide": 2
}, },
{ {
"GroupName": "App.Setting", "GroupName": "App.Setting",
@ -7796,14 +7796,6 @@
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 2 "MultiTenancySide": 2
}, },
{
"GroupName": "App.ForumManagement",
"Name": "App.ForumManagement.Publish",
"ParentName": "App.ForumManagement",
"DisplayName": "Publish",
"IsEnabled": true,
"MultiTenancySide": 3
},
{ {
"GroupName": "App.ForumManagement", "GroupName": "App.ForumManagement",
"Name": "App.ForumManagement.Create", "Name": "App.ForumManagement.Create",
@ -7835,6 +7827,14 @@
"DisplayName": "Update", "DisplayName": "Update",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 2 "MultiTenancySide": 2
},
{
"GroupName": "App.ForumManagement",
"Name": "App.ForumManagement.Publish",
"ParentName": null,
"DisplayName": "Publish",
"IsEnabled": true,
"MultiTenancySide": 3
} }
], ],
"Sectors": [ "Sectors": [

View file

@ -82,7 +82,7 @@ define(['./workbox-54d0af47'], (function (workbox) { 'use strict';
"revision": "3ca0b8505b4bec776b69afdba2768812" "revision": "3ca0b8505b4bec776b69afdba2768812"
}, { }, {
"url": "index.html", "url": "index.html",
"revision": "0.m83v8d1s4bo" "revision": "0.3kkdvt11rc8"
}], {}); }], {});
workbox.cleanupOutdatedCaches(); workbox.cleanupOutdatedCaches();
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), { workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {

View file

@ -9,6 +9,12 @@ export const getTenants = (skipCount = 0, maxResultCount = 10) =>
url: `/api/app/platform-tenant?skipCount=${skipCount}&maxResultCount=${maxResultCount}`, url: `/api/app/platform-tenant?skipCount=${skipCount}&maxResultCount=${maxResultCount}`,
}) })
export const getTenantByName = (name: string) =>
apiService.fetchData<TenantDto>({
method: 'GET',
url: `/api/app/platform-tenant/by-name?name=${encodeURIComponent(name)}`,
})
export const getTenantById = (id: string) => export const getTenantById = (id: string) =>
apiService.fetchData<TenantDto>({ apiService.fetchData<TenantDto>({
method: 'GET', method: 'GET',

View file

@ -49,9 +49,9 @@ authApiService.interceptors.response.use(
) )
authApiService.interceptors.request.use(async (config) => { authApiService.interceptors.request.use(async (config) => {
const { tenantId } = store.getState().auth const { currentTenantName } = store.getState().locale
if (tenantId) { if (currentTenantName) {
config.headers['__tenant'] = tenantId config.headers['__tenant'] = currentTenantName
} else { } else {
config.headers.delete('__tenant') config.headers.delete('__tenant')
} }

View file

@ -120,7 +120,7 @@ class ForumService {
const response = await apiService.fetchData<ForumCategory>({ const response = await apiService.fetchData<ForumCategory>({
url: '/api/app/forum/category', url: '/api/app/forum/category',
method: 'POST', method: 'POST',
data, data: {...data},
}) })
return response.data return response.data
} }
@ -181,7 +181,7 @@ class ForumService {
const response = await apiService.fetchData<ForumTopic>({ const response = await apiService.fetchData<ForumTopic>({
url: '/api/app/forum/topic', url: '/api/app/forum/topic',
method: 'POST', method: 'POST',
data, data: {...data},
}) })
return response.data return response.data
} }
@ -288,7 +288,7 @@ class ForumService {
const response = await apiService.fetchData<ForumPost>({ const response = await apiService.fetchData<ForumPost>({
url: '/api/app/forum/post', url: '/api/app/forum/post',
method: 'POST', method: 'POST',
data, data: {...data},
}) })
return response.data return response.data
} }

View file

@ -34,9 +34,9 @@ platformApiService.interceptors.request.use(async (config) => {
config.headers['Accept-Language'] = cultureName config.headers['Accept-Language'] = cultureName
} }
const { tenantId } = state.auth const { currentTenantName } = state.locale
if (tenantId) { if (currentTenantName) {
config.headers['__tenant'] = tenantId config.headers['__tenant'] = currentTenantName
} else { } else {
config.headers.delete('__tenant') config.headers.delete('__tenant')
} }

View file

@ -21,7 +21,10 @@ export interface AuthStoreModel {
name: string name: string
avatar?: string avatar?: string
} }
tenantId?: string tenant?: {
tenantId?: string
tenantName?: string
}
} }
export interface AuthStoreActions { export interface AuthStoreActions {
@ -36,7 +39,9 @@ export interface AuthStoreActions {
user: { user: {
setUser: Action<AuthStoreModel['user'], AuthStoreModel['user']> setUser: Action<AuthStoreModel['user'], AuthStoreModel['user']>
} }
setTenantId: Action<AuthStoreModel, string | undefined> tenant: {
setTenant: Action<NonNullable<AuthStoreModel['tenant']>, AuthStoreModel['tenant']>
}
} }
export type AuthModel = AuthStoreModel & AuthStoreActions export type AuthModel = AuthStoreModel & AuthStoreActions
@ -52,7 +57,10 @@ export const initialState: AuthStoreModel = {
name: '', name: '',
avatar: '', avatar: '',
}, },
tenantId: undefined, tenant: {
tenantId: '',
tenantName: '',
},
} }
export const authModel: AuthModel = { export const authModel: AuthModel = {
@ -70,9 +78,10 @@ export const authModel: AuthModel = {
state.user.userName = payload.user.userName state.user.userName = payload.user.userName
state.user.authority = payload.user.authority state.user.authority = payload.user.authority
state.user.email = payload.user.email state.user.email = payload.user.email
state.user.avatar = AVATAR_URL(payload.user.id, state.tenantId)+ `?${dayjs().unix()}` state.user.avatar = AVATAR_URL(payload.user.id, state.tenant?.tenantId) + `?${dayjs().unix()}`
}), }),
signOut: action((state) => ({ ...initialState, tenantId: state.tenantId })), signOut: action(() => ({ ...initialState })),
// signOut: action((state) => ({ ...initialState, tenantId: state.tenant?.tenantId })),
onSignInAndOut: thunkOn( onSignInAndOut: thunkOn(
(actions, storeActions) => [storeActions.auth.signIn, storeActions.auth.signOut], (actions, storeActions) => [storeActions.auth.signIn, storeActions.auth.signOut],
async (actions, payload, { getStoreActions }) => { async (actions, payload, { getStoreActions }) => {
@ -94,8 +103,11 @@ export const authModel: AuthModel = {
state.avatar = payload.avatar state.avatar = payload.avatar
}), }),
}, },
tenantId: initialState.tenantId, tenant: {
setTenantId: action((state, payload) => { ...initialState.tenant,
state.tenantId = payload setTenant: action((state, payload) => {
}), state.tenantId = payload?.tenantId
state.tenantName = payload?.tenantName
}),
},
} }

View file

@ -6,19 +6,22 @@ import { Injections, StoreModel } from '.'
export interface LocaleStoreModel { export interface LocaleStoreModel {
currentLang: string currentLang: string
currentUiVersion: string | undefined currentUiVersion: string | undefined
currentTenantName?: string
} }
export interface LocaleStoreActions { export interface LocaleStoreActions {
setLang: Action<LocaleStoreModel, string> setLang: Action<LocaleStoreModel, string>
onSetLang: ThunkOn<LocaleModel, Injections, StoreModel> onSetLang: ThunkOn<LocaleModel, Injections, StoreModel>
setUiVersion: Action<LocaleStoreModel, string | undefined> setUiVersion: Action<LocaleStoreModel, string | undefined>
setTenantName: Action<LocaleStoreModel, string | undefined>
} }
export type LocaleModel = LocaleStoreModel & LocaleStoreActions export type LocaleModel = LocaleStoreModel & LocaleStoreActions
const initialState: LocaleStoreModel = { const initialState: LocaleStoreModel = {
currentLang: appConfig.locale, currentLang: appConfig.locale,
currentUiVersion: appConfig.uiVersion currentUiVersion: appConfig.uiVersion,
currentTenantName: undefined
} }
export const localeModel: LocaleModel = { export const localeModel: LocaleModel = {
@ -36,4 +39,7 @@ export const localeModel: LocaleModel = {
setUiVersion: action((state, payload) => { setUiVersion: action((state, payload) => {
state.currentUiVersion = payload state.currentUiVersion = payload
}), }),
setTenantName: action((state, payload) => {
state.currentTenantName = payload
}),
} }

View file

@ -9,6 +9,7 @@ import { FormContainer, FormItem } from '@/components/ui/Form'
import Input from '@/components/ui/Input' import Input from '@/components/ui/Input'
import PlatformLoginResultType from '@/constants/login.result.enum' import PlatformLoginResultType from '@/constants/login.result.enum'
import { ROUTES_ENUM } from '@/constants/route.constant' import { ROUTES_ENUM } from '@/constants/route.constant'
import { getTenantByName } from '@/proxy/admin/tenant/tenant.service'
import { useStoreActions, useStoreState } from '@/store' import { useStoreActions, useStoreState } from '@/store'
import useAuth from '@/utils/hooks/useAuth' import useAuth from '@/utils/hooks/useAuth'
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
@ -43,7 +44,10 @@ const validationSchema = Yup.object().shape({
const Login = () => { const Login = () => {
const navigate = useNavigate() const navigate = useNavigate()
const isMultiTenant = useStoreState((a) => a.abpConfig.config?.multiTenancy.isEnabled) const isMultiTenant = useStoreState((a) => a.abpConfig.config?.multiTenancy.isEnabled)
const { setTenantId } = useStoreActions((a) => a.auth) const { setTenant } = useStoreActions((a) => a.auth.tenant)
const tenantName = useStoreState((state) => state.locale.currentTenantName)
const { setTenantName } = useStoreActions((actions) => actions.locale)
const [message, setMessage] = useState('') const [message, setMessage] = useState('')
const [error, setError] = useTimeOutMessage(300000) const [error, setError] = useTimeOutMessage(300000)
@ -164,13 +168,36 @@ const Login = () => {
setShowCaptcha(false) setShowCaptcha(false)
setError('') setError('')
setMessage('') setMessage('')
//Tenant belirlenmişse
fetchDataByName(tenantName || '')
} }
setSubmitting(false) setSubmitting(false)
} }
const fetchDataByName = async (name: string) => {
if (name) {
const response = await getTenantByName(name)
if (response.data) {
setTenant({ tenantId: response.data.id, tenantName: response.data.name })
} else {
setTenant(undefined)
}
} else {
setTenant(undefined)
}
}
const subDomainName = getSubdomain() const subDomainName = getSubdomain()
const tenantId = useStoreState((a) => a.auth.tenantId) ?? subDomainName useEffect(() => {
if (subDomainName) {
setTenantName(subDomainName)
fetchDataByName(subDomainName)
}
}, [subDomainName])
const tenantStyle: React.CSSProperties | undefined = const tenantStyle: React.CSSProperties | undefined =
subDomainName && subDomainName !== defaultSubDomain subDomainName && subDomainName !== defaultSubDomain
? { ? {
@ -184,23 +211,6 @@ const Login = () => {
} }
: undefined : undefined
const { config } = useStoreState((state) => state.abpConfig)
const { setLang } = useStoreActions((actions) => actions.locale)
const currentCulture = config?.localization?.currentCulture?.cultureName
const languageList = config?.localization.languages
useEffect(() => {
if (!isMultiTenant) return
const subDomainName = getSubdomain()
if (subDomainName?.toUpperCase() === defaultSubDomain) {
setTenantId('')
} else {
setTenantId(subDomainName || '')
}
}, [isMultiTenant])
return ( return (
<motion.div <motion.div
initial={{ opacity: 0, x: 100 }} initial={{ opacity: 0, x: 100 }}
@ -220,8 +230,8 @@ const Login = () => {
<div className="mb-4"> <div className="mb-4">
<Input <Input
placeholder={translate('::Sirket')} placeholder={translate('::Sirket')}
value={tenantId || ''} value={tenantName}
onChange={(e) => setTenantId(e.target.value)} onChange={(e) => setTenantName(e.target.value)}
style={tenantStyle} style={tenantStyle}
aria-hidden={subDomainName && subDomainName !== defaultSubDomain ? 'true' : 'false'} aria-hidden={subDomainName && subDomainName !== defaultSubDomain ? 'true' : 'false'}
/> />

View file

@ -109,7 +109,7 @@ const Profile = () => {
setUser({ setUser({
...auth.user, ...auth.user,
name: `${resp.data.name} ${resp.data.surname}`.trim(), name: `${resp.data.name} ${resp.data.surname}`.trim(),
avatar: AVATAR_URL(auth.user.id, auth.tenantId) + `?${dayjs().unix()}`, avatar: AVATAR_URL(auth.user.id, auth.tenant.tenantId) + `?${dayjs().unix()}`,
}) })
toast.push(<Notification title={'Profil güncellendi'} type="success" />, { toast.push(<Notification title={'Profil güncellendi'} type="success" />, {

View file

@ -1,5 +1,10 @@
import { ForumCategory, ForumPost, ForumTopic } from '@/proxy/forum/forum' import { ForumCategory, ForumPost, ForumTopic } from '@/proxy/forum/forum'
import { forumService } from '@/services/forumService' import {
CreateCategoryRequest,
CreatePostRequest,
CreateTopicRequest,
forumService,
} from '@/services/forumService'
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
export function useForumData() { export function useForumData() {
@ -56,15 +61,7 @@ export function useForumData() {
} }
// Category operations // Category operations
const createCategory = async (categoryData: { const createCategory = async (categoryData: CreateCategoryRequest) => {
name: string
slug: string
description: string
icon: string
displayOrder: number
isActive: boolean
isLocked: boolean
}) => {
try { try {
setLoading(true) setLoading(true)
const newCategory = await forumService.createCategory(categoryData) const newCategory = await forumService.createCategory(categoryData)
@ -99,7 +96,7 @@ export function useForumData() {
await loadCategories() // refresh after update await loadCategories() // refresh after update
} }
const updateCategoryActiveState = async (id: string) => { const updateCategoryActiveState = async (id: string) => {
await forumService.updateCategoryActiveState(id) await forumService.updateCategoryActiveState(id)
await loadCategories() // refresh after update await loadCategories() // refresh after update
} }
@ -124,13 +121,7 @@ export function useForumData() {
} }
// Topic operations // Topic operations
const createTopic = async (topicData: { const createTopic = async (topicData: CreateTopicRequest) => {
title: string
content: string
categoryId: string
isPinned?: boolean
isLocked?: boolean
}) => {
try { try {
setLoading(true) setLoading(true)
const newTopic = await forumService.createTopic(topicData) const newTopic = await forumService.createTopic(topicData)
@ -273,11 +264,7 @@ export function useForumData() {
} }
// Post operations // Post operations
const createPost = async (postData: { const createPost = async (postData: CreatePostRequest) => {
topicId: string
content: string
parentPostId?: string
}) => {
try { try {
setLoading(true) setLoading(true)
const newPost = await forumService.createPost(postData) const newPost = await forumService.createPost(postData)