mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-16 16:30:15 +01:00
feat: add sample multi-user support
feat: update README
This commit is contained in:
parent
41f351786f
commit
62d88380e0
19 changed files with 314 additions and 49 deletions
31
README.md
31
README.md
|
|
@ -84,6 +84,7 @@ Currently, this project is only functional with the `text-davinci-003` model.
|
|||
- [Docker](#docker)
|
||||
- [Access Tokens](#access-tokens)
|
||||
- [Proxy](#proxy)
|
||||
- [User System](#user-system)
|
||||
- [Updating](#updating)
|
||||
- [Use Cases](#use-cases)
|
||||
- [Origin](#origin)
|
||||
|
|
@ -235,6 +236,36 @@ set in docker-compose.yml file, under services - api - environment
|
|||
|
||||
</details>
|
||||
|
||||
### User System
|
||||
|
||||
By default, there is no user system enabled, so anyone can access your server.
|
||||
|
||||
**This project is not designed to provide a complete and full-featured user system.** It's not high priority task and might never be provided.
|
||||
|
||||
[wtlyu](https://github.com/wtlyu) provide a sample user system structure, that you can implement your own user system. It's simple and not a ready-for-use edition.
|
||||
|
||||
(If you want to implement your user system, open this ↓)
|
||||
|
||||
<details>
|
||||
<summary><strong>Implement your own user system </strong></summary>
|
||||
|
||||
To enable the user system, set `ENABLE_USER_SYSTEM=1` in your `.env` file.
|
||||
|
||||
The sample structure is simple. It provide three basic endpoint:
|
||||
|
||||
1. `/auth/login` will redirect to your own login url. In the sample code, it's `/auth/your_login_page`.
|
||||
2. `/auth/logout` will redirect to your own logout url. In the sample code, it's `/auth/your_login_page/logout`.
|
||||
3. `/api/me` will return the userinfo: `{ username, display }`.
|
||||
1. `username` will be used in db, used to distinguish between users.
|
||||
2. `display` will be displayed in UI.
|
||||
|
||||
The only one thing that drive user system work is `req.session.user`. Once it's set, the client will be trusted. Set to `null` if logout.
|
||||
|
||||
Please refer to `/api/server/routes/authYoutLogin.js` file. It's very clear and simple to tell you how to implement your user system.
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
### Updating
|
||||
- As the project is still a work-in-progress, you should pull the latest and run the steps over. Reset your browser cache/clear site data.
|
||||
|
||||
|
|
|
|||
|
|
@ -20,3 +20,10 @@ MONGO_URI="mongodb://127.0.0.1:27017/chatgpt-clone"
|
|||
OPENAI_KEY=
|
||||
CHATGPT_TOKEN=
|
||||
BING_TOKEN=
|
||||
|
||||
# User System
|
||||
|
||||
# global enable/disable the sample user system.
|
||||
# this is not a ready to use user system.
|
||||
# dont't use it, unless you can write your own code.
|
||||
ENABLE_USER_SYSTEM=
|
||||
|
|
|
|||
|
|
@ -43,6 +43,9 @@ const convoSchema = mongoose.Schema(
|
|||
type: String,
|
||||
required: true
|
||||
},
|
||||
user: {
|
||||
type: String
|
||||
},
|
||||
suggestions: [{ type: String }],
|
||||
messages: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Message' }]
|
||||
},
|
||||
|
|
@ -52,9 +55,9 @@ const convoSchema = mongoose.Schema(
|
|||
const Conversation =
|
||||
mongoose.models.Conversation || mongoose.model('Conversation', convoSchema);
|
||||
|
||||
const getConvo = async (conversationId) => {
|
||||
const getConvo = async (user, conversationId) => {
|
||||
try {
|
||||
return await Conversation.findOne({ conversationId }).exec();
|
||||
return await Conversation.findOne({ user, conversationId }).exec();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return { message: 'Error getting single conversation' };
|
||||
|
|
@ -62,12 +65,13 @@ const getConvo = async (conversationId) => {
|
|||
};
|
||||
|
||||
module.exports = {
|
||||
saveConvo: async ({ conversationId, newConversationId, title, ...convo }) => {
|
||||
saveConvo: async (user, { conversationId, newConversationId, title, ...convo }) => {
|
||||
try {
|
||||
const messages = await getMessages({ conversationId });
|
||||
const update = { ...convo, messages };
|
||||
if (title) {
|
||||
update.title = title;
|
||||
update.user = user
|
||||
}
|
||||
if (newConversationId) {
|
||||
update.conversationId = newConversationId;
|
||||
|
|
@ -81,8 +85,10 @@ module.exports = {
|
|||
update.promptPrefix = null;
|
||||
}
|
||||
|
||||
console.error(user)
|
||||
|
||||
return await Conversation.findOneAndUpdate(
|
||||
{ conversationId },
|
||||
{ conversationId: conversationId, user: user },
|
||||
{ $set: update },
|
||||
{ new: true, upsert: true }
|
||||
).exec();
|
||||
|
|
@ -91,9 +97,9 @@ module.exports = {
|
|||
return { message: 'Error saving conversation' };
|
||||
}
|
||||
},
|
||||
updateConvo: async ({ conversationId, ...update }) => {
|
||||
updateConvo: async (user, { conversationId, ...update }) => {
|
||||
try {
|
||||
return await Conversation.findOneAndUpdate({ conversationId }, update, {
|
||||
return await Conversation.findOneAndUpdate({ conversationId: conversationId, user: user }, update, {
|
||||
new: true
|
||||
}).exec();
|
||||
} catch (error) {
|
||||
|
|
@ -101,12 +107,11 @@ module.exports = {
|
|||
return { message: 'Error updating conversation' };
|
||||
}
|
||||
},
|
||||
// getConvos: async () => await Conversation.find({}).sort({ createdAt: -1 }).exec(),
|
||||
getConvosByPage: async (pageNumber = 1, pageSize = 12) => {
|
||||
getConvosByPage: async (user, pageNumber = 1, pageSize = 12) => {
|
||||
try {
|
||||
const totalConvos = (await Conversation.countDocuments()) || 1;
|
||||
const totalConvos = (await Conversation.countDocuments({ user: user })) || 1;
|
||||
const totalPages = Math.ceil(totalConvos / pageSize);
|
||||
const convos = await Conversation.find()
|
||||
const convos = await Conversation.find({ user: user })
|
||||
.sort({ createdAt: -1, created: -1 })
|
||||
.skip((pageNumber - 1) * pageSize)
|
||||
.limit(pageSize)
|
||||
|
|
@ -119,17 +124,17 @@ module.exports = {
|
|||
}
|
||||
},
|
||||
getConvo,
|
||||
getConvoTitle: async (conversationId) => {
|
||||
getConvoTitle: async (user, conversationId) => {
|
||||
try {
|
||||
const convo = await getConvo(conversationId);
|
||||
const convo = await getConvo(user, conversationId);
|
||||
return convo.title;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return { message: 'Error getting conversation title' };
|
||||
}
|
||||
},
|
||||
deleteConvos: async (filter) => {
|
||||
let deleteCount = await Conversation.deleteMany(filter).exec();
|
||||
deleteConvos: async (user, filter) => {
|
||||
let deleteCount = await Conversation.deleteMany({...filter, user: user}).exec();
|
||||
deleteCount.messages = await deleteMessages(filter);
|
||||
return deleteCount;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -22,9 +22,11 @@
|
|||
"@keyv/mongo": "^2.1.8",
|
||||
"@vscode/vscode-languagedetection": "^1.0.22",
|
||||
"@waylaidwanderer/chatgpt-api": "^1.28.2",
|
||||
"axios": "^1.3.4",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.0.3",
|
||||
"express": "^4.18.2",
|
||||
"express-session": "^1.17.3",
|
||||
"keyv": "^4.5.2",
|
||||
"keyv-file": "^0.2.0",
|
||||
"lodash": "^4.17.21",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
const express = require('express');
|
||||
const session = require('express-session')
|
||||
const dbConnect = require('../models/dbConnect');
|
||||
const { migrateDb } = require('../models');
|
||||
const path = require('path');
|
||||
|
|
@ -7,6 +8,7 @@ const routes = require('./routes');
|
|||
const app = express();
|
||||
const port = process.env.PORT || 3080;
|
||||
const host = process.env.HOST || 'localhost'
|
||||
const userSystemEnabled = process.env.ENABLE_USER_SYSTEM || false
|
||||
const projectPath = path.join(__dirname, '..', '..', 'client');
|
||||
dbConnect().then(() => {
|
||||
console.log('Connected to MongoDB');
|
||||
|
|
@ -16,17 +18,38 @@ dbConnect().then(() => {
|
|||
app.use(cors());
|
||||
app.use(express.json());
|
||||
app.use(express.static(path.join(projectPath, 'public')));
|
||||
app.set('trust proxy', 1) // trust first proxy
|
||||
app.use(session({
|
||||
secret: 'chatgpt-clone-random-secrect',
|
||||
resave: false,
|
||||
saveUninitialized: true,
|
||||
}))
|
||||
|
||||
app.get('/', function (req, res) {
|
||||
app.get('/', routes.authenticatedOrRedirect, function (req, res) {
|
||||
console.log(path.join(projectPath, 'public', 'index.html'));
|
||||
res.sendFile(path.join(projectPath, 'public', 'index.html'));
|
||||
});
|
||||
|
||||
app.use('/api/ask', routes.ask);
|
||||
app.use('/api/messages', routes.messages);
|
||||
app.use('/api/convos', routes.convos);
|
||||
app.use('/api/customGpts', routes.customGpts);
|
||||
app.use('/api/prompts', routes.prompts);
|
||||
app.get('/api/me', function (req, res) {
|
||||
if (userSystemEnabled) {
|
||||
const user = req?.session?.user
|
||||
|
||||
if (user)
|
||||
res.send(JSON.stringify({username: user?.username, display: user?.display}));
|
||||
else
|
||||
res.send(JSON.stringify(null));
|
||||
} else {
|
||||
res.send(JSON.stringify({username: 'anonymous_user', display: 'Anonymous User'}));
|
||||
}
|
||||
});
|
||||
|
||||
app.use('/api/ask', routes.authenticatedOr401, routes.ask);
|
||||
app.use('/api/messages', routes.authenticatedOr401, routes.messages);
|
||||
app.use('/api/convos', routes.authenticatedOr401, routes.convos);
|
||||
app.use('/api/customGpts', routes.authenticatedOr401, routes.customGpts);
|
||||
app.use('/api/prompts', routes.authenticatedOr401, routes.prompts);
|
||||
app.use('/auth', routes.auth);
|
||||
|
||||
|
||||
app.listen(port, host, () => {
|
||||
if (host=='0.0.0.0')
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ const ask = async ({
|
|||
gptResponse.parentMessageId = overrideParentMessageId || userMessageId;
|
||||
|
||||
await saveMessage(gptResponse);
|
||||
await saveConvo(gptResponse);
|
||||
await saveConvo(req?.session?.user?.username, gptResponse);
|
||||
sendMessage(res, {
|
||||
title: await getConvoTitle(conversationId),
|
||||
final: true,
|
||||
|
|
|
|||
|
|
@ -129,7 +129,8 @@ const ask = async ({
|
|||
|
||||
response.text = await handleText(response, true);
|
||||
await saveMessage(response);
|
||||
await saveConvo({ ...response, model, chatGptLabel: null, promptPrefix: null, ...convo });
|
||||
await saveConvo(req?.session?.user?.username, { ...response, model, chatGptLabel: null, promptPrefix: null, ...convo });
|
||||
|
||||
sendMessage(res, {
|
||||
title: await getConvoTitle(conversationId),
|
||||
final: true,
|
||||
|
|
|
|||
|
|
@ -141,7 +141,8 @@ const ask = async ({
|
|||
response.text = await handleText(response, true);
|
||||
// Save sydney response & convo, then send
|
||||
await saveMessage(response);
|
||||
await saveConvo({ ...response, model, chatGptLabel: null, promptPrefix: null, ...convo });
|
||||
await saveConvo(req?.session?.user?.username, { ...response, model, chatGptLabel: null, promptPrefix: null, ...convo });
|
||||
|
||||
sendMessage(res, {
|
||||
title: await getConvoTitle(conversationId),
|
||||
final: true,
|
||||
|
|
|
|||
46
api/server/routes/auth.js
Normal file
46
api/server/routes/auth.js
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const authYourLogin = require('./authYourLogin');
|
||||
const userSystemEnabled = process.env.ENABLE_USER_SYSTEM || false
|
||||
|
||||
router.get('/login', function (req, res) {
|
||||
if (userSystemEnabled)
|
||||
res.redirect('/auth/your_login_page')
|
||||
else
|
||||
res.redirect('/')
|
||||
})
|
||||
|
||||
router.get('/logout', function (req, res) {
|
||||
// clear the session
|
||||
req.session.user = null
|
||||
|
||||
req.session.save(function (error) {
|
||||
if (userSystemEnabled)
|
||||
res.redirect('/auth/your_login_page/logout')
|
||||
else
|
||||
res.redirect('/')
|
||||
})
|
||||
})
|
||||
|
||||
const authenticatedOr401 = (req, res, next) => {
|
||||
if (userSystemEnabled) {
|
||||
const user = req?.session?.user;
|
||||
|
||||
if (user) next();
|
||||
else res.status(401).end();
|
||||
} else next();
|
||||
}
|
||||
|
||||
const authenticatedOrRedirect = (req, res, next) => {
|
||||
if (userSystemEnabled) {
|
||||
const user = req?.session?.user;
|
||||
|
||||
if (user) next();
|
||||
else res.redirect('/auth/login').end();
|
||||
} else next();
|
||||
}
|
||||
|
||||
if (userSystemEnabled)
|
||||
router.use('/your_login_page', authYourLogin);
|
||||
|
||||
module.exports = { router, authenticatedOr401, authenticatedOrRedirect };
|
||||
40
api/server/routes/authYourLogin.js
Normal file
40
api/server/routes/authYourLogin.js
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
const express = require('express');
|
||||
const router = express.Router();
|
||||
|
||||
// WARNING!
|
||||
// THIS IS NOT A READY TO USE USER SYSTEM
|
||||
// PLEASE IMPLEMENT YOUR OWN USER SYSTEM
|
||||
|
||||
const userSystemEnabled = process.env.ENABLE_USER_SYSTEM || false
|
||||
|
||||
// Logout
|
||||
router.get('/logout', (req, res) => {
|
||||
// Do anything you want
|
||||
console.warn('logout not implemented!')
|
||||
|
||||
// finish
|
||||
res.redirect('/')
|
||||
});
|
||||
|
||||
// Login
|
||||
router.get('/', async (req, res) => {
|
||||
// Do anything you want
|
||||
console.warn('login not implemented! Automatic passed as sample user')
|
||||
|
||||
// save the user info into session
|
||||
// username will be used in db
|
||||
// display will be used in UI
|
||||
req.session.user = {
|
||||
username: 'sample_user',
|
||||
display: 'Sample User',
|
||||
}
|
||||
|
||||
req.session.save(function (error) {
|
||||
if (error) {
|
||||
console.log(error);
|
||||
res.send(`<h1>Login Failed. An error occurred. Please see the server logs for details.</h1>`);
|
||||
} else res.redirect('/')
|
||||
})
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
|
@ -1,10 +1,38 @@
|
|||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { titleConvo } = require('../../app/');
|
||||
const { getConvo, saveConvo, getConvoTitle } = require('../../models');
|
||||
const { getConvosByPage, deleteConvos, updateConvo } = require('../../models/Conversation');
|
||||
const { getMessages } = require('../../models/Message');
|
||||
|
||||
router.get('/', async (req, res) => {
|
||||
const pageNumber = req.query.pageNumber || 1;
|
||||
res.status(200).send(await getConvosByPage(pageNumber));
|
||||
res.status(200).send(await getConvosByPage(req?.session?.user?.username, pageNumber));
|
||||
});
|
||||
|
||||
router.post('/gen_title', async (req, res) => {
|
||||
const { conversationId } = req.body.arg;
|
||||
|
||||
const convo = await getConvo(req?.session?.user?.username, conversationId)
|
||||
const firstMessage = (await getMessages({ conversationId }))[0]
|
||||
const secondMessage = (await getMessages({ conversationId }))[1]
|
||||
|
||||
const title = convo.jailbreakConversationId
|
||||
? await getConvoTitle(conversationId)
|
||||
: await titleConvo({
|
||||
model: convo?.model,
|
||||
message: firstMessage?.text,
|
||||
response: JSON.stringify(secondMessage?.text || '')
|
||||
});
|
||||
|
||||
await saveConvo(req?.session?.user?.username,
|
||||
{
|
||||
conversationId,
|
||||
title
|
||||
}
|
||||
)
|
||||
|
||||
res.status(200).send(title);
|
||||
});
|
||||
|
||||
router.post('/clear', async (req, res) => {
|
||||
|
|
@ -15,7 +43,7 @@ router.post('/clear', async (req, res) => {
|
|||
}
|
||||
|
||||
try {
|
||||
const dbResponse = await deleteConvos(filter);
|
||||
const dbResponse = await deleteConvos(req?.session?.user?.username, filter);
|
||||
res.status(201).send(dbResponse);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
|
@ -27,7 +55,7 @@ router.post('/update', async (req, res) => {
|
|||
const update = req.body.arg;
|
||||
|
||||
try {
|
||||
const dbResponse = await updateConvo(update);
|
||||
const dbResponse = await updateConvo(req?.session?.user?.username, update);
|
||||
res.status(201).send(dbResponse);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
|
|
|||
|
|
@ -3,5 +3,6 @@ const messages = require('./messages');
|
|||
const convos = require('./convos');
|
||||
const customGpts = require('./customGpts');
|
||||
const prompts = require('./prompts');
|
||||
const { router: auth, authenticatedOr401, authenticatedOrRedirect } = require('./auth');
|
||||
|
||||
module.exports = { ask, messages, convos, customGpts, prompts };
|
||||
module.exports = { ask, messages, convos, customGpts, prompts, auth, authenticatedOr401, authenticatedOrRedirect };
|
||||
|
|
@ -5,34 +5,67 @@ import TextChat from './components/Main/TextChat';
|
|||
import Nav from './components/Nav';
|
||||
import MobileNav from './components/Nav/MobileNav';
|
||||
import useDocumentTitle from '~/hooks/useDocumentTitle';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import { setUser } from './store/userReducer';
|
||||
import axios from 'axios'
|
||||
|
||||
const App = () => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const { messages, messageTree } = useSelector((state) => state.messages);
|
||||
const { user } = useSelector((state) => state.user);
|
||||
const { title } = useSelector((state) => state.convo);
|
||||
const { conversationId } = useSelector((state) => state.convo);
|
||||
const [ navVisible, setNavVisible ]= useState(false)
|
||||
useDocumentTitle(title);
|
||||
|
||||
return (
|
||||
<div className="flex h-screen">
|
||||
<Nav navVisible={navVisible} setNavVisible={setNavVisible} />
|
||||
<div className="flex h-full w-full flex-1 flex-col bg-gray-50 md:pl-[260px]">
|
||||
<div className="transition-width relative flex h-full w-full flex-1 flex-col items-stretch overflow-hidden bg-white dark:bg-gray-800">
|
||||
<MobileNav setNavVisible={setNavVisible} />
|
||||
{messages.length === 0 ? (
|
||||
<Landing title={title} />
|
||||
) : (
|
||||
<Messages
|
||||
messages={messages}
|
||||
messageTree={messageTree}
|
||||
/>
|
||||
)}
|
||||
<TextChat messages={messages} />
|
||||
useEffect(() => {
|
||||
axios.get('/api/me', {
|
||||
timeout: 1000,
|
||||
withCredentials: true
|
||||
}).then((res) => {
|
||||
return res.data
|
||||
}).then((user) => {
|
||||
if (user)
|
||||
dispatch(setUser(user))
|
||||
else {
|
||||
console.log('Not login!')
|
||||
window.location.href = "/auth/login";
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
console.log('Not login!')
|
||||
window.location.href = "/auth/login";
|
||||
})
|
||||
// setUser
|
||||
}, [])
|
||||
|
||||
if (user)
|
||||
return (
|
||||
<div className="flex h-screen">
|
||||
<Nav navVisible={navVisible} setNavVisible={setNavVisible} />
|
||||
<div className="flex h-full w-full flex-1 flex-col bg-gray-50 md:pl-[260px]">
|
||||
<div className="transition-width relative flex h-full w-full flex-1 flex-col items-stretch overflow-hidden bg-white dark:bg-gray-800">
|
||||
<MobileNav setNavVisible={setNavVisible} />
|
||||
{messages.length === 0 ? (
|
||||
<Landing title={title} />
|
||||
) : (
|
||||
<Messages
|
||||
messages={messages}
|
||||
messageTree={messageTree}
|
||||
/>
|
||||
)}
|
||||
<TextChat messages={messages} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
);
|
||||
else
|
||||
return (
|
||||
<div className="flex h-screen">
|
||||
|
||||
</div>
|
||||
)
|
||||
};
|
||||
|
||||
export default App;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ export default function TextChat({ messages }) {
|
|||
const inputRef = useRef(null)
|
||||
const isComposing = useRef(false);
|
||||
const dispatch = useDispatch();
|
||||
const { user } = useSelector((state) => state.user);
|
||||
const convo = useSelector((state) => state.convo);
|
||||
const { initial } = useSelector((state) => state.models);
|
||||
const { isSubmitting, stopStream, submission, disabled, model, chatGptLabel, promptPrefix } =
|
||||
|
|
|
|||
23
client/src/components/Nav/Logout.jsx
Normal file
23
client/src/components/Nav/Logout.jsx
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import React, { useState, useContext } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import LogOutIcon from '../svg/LogOutIcon';
|
||||
|
||||
|
||||
export default function Logout() {
|
||||
const { user } = useSelector((state) => state.user);
|
||||
|
||||
const clickHandler = () => {
|
||||
window.location.href = "/auth/logout";
|
||||
};
|
||||
|
||||
return (
|
||||
<a
|
||||
className="flex cursor-pointer items-center gap-3 rounded-md py-3 px-3 text-sm text-white transition-colors duration-200 hover:bg-gray-500/10"
|
||||
onClick={clickHandler}
|
||||
>
|
||||
<LogOutIcon />
|
||||
{user?.display || user?.username || 'USER'}
|
||||
<small>Log out</small>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
|
@ -3,16 +3,18 @@ import NavLink from './NavLink';
|
|||
import LogOutIcon from '../svg/LogOutIcon';
|
||||
import ClearConvos from './ClearConvos';
|
||||
import DarkMode from './DarkMode';
|
||||
import Logout from './Logout';
|
||||
|
||||
export default function NavLinks() {
|
||||
return (
|
||||
<>
|
||||
<ClearConvos />
|
||||
<DarkMode />
|
||||
<NavLink
|
||||
<Logout />
|
||||
{/* <NavLink
|
||||
svg={LogOutIcon}
|
||||
text="Log out"
|
||||
/>
|
||||
/> */}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import messageReducer from './messageSlice.js'
|
|||
import modelReducer from './modelSlice.js'
|
||||
import submitReducer from './submitSlice.js'
|
||||
import textReducer from './textSlice.js'
|
||||
import userReducer from './userReducer.js'
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
|
|
@ -13,6 +14,7 @@ export const store = configureStore({
|
|||
models: modelReducer,
|
||||
text: textReducer,
|
||||
submit: submitReducer,
|
||||
user: userReducer,
|
||||
},
|
||||
devTools: true,
|
||||
});
|
||||
19
client/src/store/userReducer.js
Normal file
19
client/src/store/userReducer.js
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
const initialState = {
|
||||
user: null,
|
||||
};
|
||||
|
||||
const currentSlice = createSlice({
|
||||
name: 'user',
|
||||
initialState,
|
||||
reducers: {
|
||||
setUser: (state, action) => {
|
||||
state.user = action.payload;
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
export const { setUser } = currentSlice.actions;
|
||||
|
||||
export default currentSlice.reducer;
|
||||
|
|
@ -3,10 +3,10 @@ import axios from 'axios';
|
|||
import useSWR from 'swr';
|
||||
import useSWRMutation from 'swr/mutation';
|
||||
|
||||
const fetcher = (url) => fetch(url).then((res) => res.json());
|
||||
const fetcher = (url) => fetch(url, {credentials: 'include'}).then((res) => res.json());
|
||||
|
||||
const postRequest = async (url, { arg }) => {
|
||||
return await axios.post(url, { arg });
|
||||
return await axios.post(url, { withCredentials: true, arg });
|
||||
};
|
||||
|
||||
export const swr = (path, successCallback, options) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue