Skip to content
Snippets Groups Projects
Commit 5038b962 authored by 세현 임's avatar 세현 임
Browse files

Merge branch 'develop' into 'master'

[#1#2#3] DB모델 객체 및 로그인 ,회원가입 구현

See merge request !5
parents 8249a4ef 36572dd6
No related branches found
No related tags found
1 merge request!5[#1#2#3] DB모델 객체 및 로그인 ,회원가입 구현
.env 0 → 100644
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=0000
DB_NAME=meeting
MONGO_URI=mongodb://localhost:27017/your_mongo_db
PORT=8080
CALLBACK_URL=http://localhost:8080/auth/google/callback
\ No newline at end of file
node_modules/ node_modules/
.env .env/
\ No newline at end of file config.json/
// app.js
require('dotenv').config();
const express = require('express'); const express = require('express');
const session = require('express-session');
const passport = require('./passport'); // 변경된 경로
const flash = require('connect-flash');
const app = express(); const app = express();
// 미들웨어 설정
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
// 세션 설정
app.use(
session({
secret: 'your_session_secret',
resave: false,
saveUninitialized: false,
})
);
// Passport 초기화 및 세션 연결
app.use(passport.initialize());
app.use(passport.session());
// 플래시 메시지 (선택 사항)
app.use(flash());
// 라우트 설정
const authRoutes = require('./routes/auth');
app.use('/auth', authRoutes);
const PORT = process.env.PORT || 3000; const PORT = process.env.PORT || 3000;
app.get('/', (req, res) => { app.get('/', (req, res) => {
......
{
"development": {
"username": "root",
"password": null,
"database": "database_development",
"host": "127.0.0.1",
"dialect": "mysql"
},
"test": {
"username": "root",
"password": null,
"database": "database_test",
"host": "127.0.0.1",
"dialect": "mysql"
},
"production": {
"username": "root",
"password": null,
"database": "database_production",
"host": "127.0.0.1",
"dialect": "mysql"
}
}
// config/mongoose.js
const mongoose = require('mongoose');
mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
mongoose.connection.on('connected', () => {
console.log('Mongoose connected.');
});
mongoose.connection.on('error', (err) => {
console.error('Mongoose connection error:', err);
});
module.exports = mongoose;
// config/sequelize.js
const { Sequelize } = require('sequelize');
const sequelize = new Sequelize(process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASSWORD, {
host: process.env.DB_HOST,
dialect: 'mysql', // 사용하려는 DBMS에 맞게 변경
logging: false,
define: {
//timestamps: true, // createdAt, updatedAt 자동 생성
underscored: true, // created_at 형식의 필드명 사용
},
});
module.exports = sequelize;
\ No newline at end of file
// middlewares/auth.js
exports.isLoggedIn = (req, res, next) => {
if (req.isAuthenticated()) {
return next();
}
res.redirect('/auth/login');
};
exports.isNotLoggedIn = (req, res, next) => {
if (!req.isAuthenticated()) {
return next();
}
res.redirect('/');
};
// models/Friend.js
const { DataTypes } = require('sequelize');
const sequelize = require('../config/sequelize');
const User = require('./User');
const Friend = sequelize.define('Friend', {
type: {
type: DataTypes.ENUM('NORMAL', 'SPECIAL'),
allowNull: false,
},
}, {
tableName: 'Friends',
timestamps: true,
});
Friend.belongsTo(User, { foreignKey: 'user_id', as: 'user' });
Friend.belongsTo(User, { foreignKey: 'friend_id', as: 'friend' });
User.hasMany(Friend, { foreignKey: 'user_id', as: 'friends' });
User.hasMany(Friend, { foreignKey: 'friend_id', as: 'friendOf' });
module.exports = Friend;
// models/Friend.js
module.exports = (sequelize, DataTypes) => {
const Friend = sequelize.define('Friend', {
id: {
type: DataTypes.BIGINT,
primaryKey: true,
autoIncrement: true,
},
user_id: {
type: DataTypes.BIGINT,
allowNull: false,
references: {
model: 'Users',
key: 'id',
},
onDelete: 'CASCADE',
},
friend_id: {
type: DataTypes.BIGINT,
allowNull: false,
references: {
model: 'Users',
key: 'id',
},
onDelete: 'CASCADE',
},
type: {
type: DataTypes.ENUM('NORMAL', 'SPECIAL'),
allowNull: false,
},
created_at: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
},
}, {
tableName: 'Friends',
timestamps: false,
indexes: [
{
unique: true,
fields: ['user_id', 'friend_id'],
},
],
});
return Friend;
};
// models/User.js // models/index.js
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
id: {
type: DataTypes.BIGINT,
primaryKey: true,
autoIncrement: true,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
validate: {
isEmail: true, // 이메일 형식 검증
},
},
invite_code: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4, // 자동으로 UUID 생성
allowNull: false,
unique: true,
},
created_at: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
},
// updated_at 추가 (필요 시)
updated_at: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
},
}, {
tableName: 'Users',
timestamps: false, // created_at과 updated_at을 수동으로 관리
});
return User; const sequelize = require('../config/sequelize');
const User = require('./User');
const Schedule = require('./Schedule');
const Meeting = require('./Meeting');
const MeetingParticipant = require('./MeetingParticipant'); //폴더명수정
const Friend = require('./Friend');
module.exports = {
sequelize,
User,
Schedule,
Meeting,
MeetingParticipant,
Friend,
}; };
// models/Meeting.js // models/Meeting.js
module.exports = (sequelize, DataTypes) => {
const { DataTypes } = require('sequelize');
const sequelize = require('../config/sequelize');
const User = require('./User');
const Meeting = sequelize.define('Meeting', { const Meeting = sequelize.define('Meeting', {
id: {
type: DataTypes.BIGINT,
primaryKey: true,
autoIncrement: true,
},
title: { title: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: false, allowNull: false,
}, },
description: { description: {
type: DataTypes.TEXT, type: DataTypes.TEXT,
allowNull: true,
}, },
start_time: { start_time: {
type: DataTypes.DATE, type: DataTypes.DATE,
...@@ -21,44 +19,23 @@ module.exports = (sequelize, DataTypes) => { ...@@ -21,44 +19,23 @@ module.exports = (sequelize, DataTypes) => {
end_time: { end_time: {
type: DataTypes.DATE, type: DataTypes.DATE,
allowNull: false, allowNull: false,
validate: {
isAfterStart(value) {
if (value <= this.start_time) {
throw new Error('end_time은 start_time 이후여야 합니다.');
}
},
},
}, },
location: { location: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: true,
}, },
deadline: { deadline: {
type: DataTypes.DATE, type: DataTypes.DATE,
allowNull: true,
}, },
type: { type: {
type: DataTypes.ENUM('OPEN', 'CLOSE'), type: DataTypes.ENUM('OPEN', 'CLOSE'),
allowNull: false, allowNull: false,
}, },
created_by: {
type: DataTypes.BIGINT,
allowNull: false,
references: {
model: 'Users',
key: 'id',
},
onDelete: 'CASCADE',
},
}, { }, {
tableName: 'Meetings', tableName: 'Meetings',
timestamps: false, timestamps: false,
indexes: [
{
fields: ['created_by'],
},
],
}); });
return Meeting; Meeting.belongsTo(User, { foreignKey: 'created_by', as: 'creator' });
}; User.hasMany(Meeting, { foreignKey: 'created_by', as: 'meetings' });
module.exports = Meeting;
// models/MeetingParticipant.js // models/MeetingParticipant.js
module.exports = (sequelize, DataTypes) => {
const MeetingParticipant = sequelize.define('MeetingParticipant', { const { DataTypes } = require('sequelize');
id: { const sequelize = require('../config/sequelize');
type: DataTypes.BIGINT, const Meeting = require('./Meeting');
primaryKey: true, const User = require('./User');
autoIncrement: true,
}, const MeetingParticipant = sequelize.define('MeetingParticipant', {}, {
meeting_id: {
type: DataTypes.BIGINT,
allowNull: false,
references: {
model: 'Meetings',
key: 'id',
},
onDelete: 'CASCADE',
},
user_id: {
type: DataTypes.BIGINT,
allowNull: false,
references: {
model: 'Users',
key: 'id',
},
onDelete: 'CASCADE',
},
}, {
tableName: 'MeetingParticipants', tableName: 'MeetingParticipants',
timestamps: false, timestamps: false,
indexes: [
{
unique: true,
fields: ['meeting_id', 'user_id'],
},
],
}); });
return MeetingParticipant; MeetingParticipant.belongsTo(Meeting, { foreignKey: 'meeting_id', as: 'meeting' });
}; Meeting.hasMany(MeetingParticipant, { foreignKey: 'meeting_id', as: 'participants' });
MeetingParticipant.belongsTo(User, { foreignKey: 'user_id', as: 'user' });
User.hasMany(MeetingParticipant, { foreignKey: 'user_id', as: 'meetingParticipations' });
module.exports = MeetingParticipant;
// models/Schedule.js // models/Schedule.js
module.exports = (sequelize, DataTypes) => {
const { DataTypes } = require('sequelize');
const sequelize = require('../config/sequelize');
const User = require('./User');
const Schedule = sequelize.define('Schedule', { const Schedule = sequelize.define('Schedule', {
id: {
type: DataTypes.BIGINT,
primaryKey: true,
autoIncrement: true,
},
user_id: {
type: DataTypes.BIGINT,
allowNull: false,
references: {
model: 'Users',
key: 'id',
},
onDelete: 'CASCADE',
},
title: { title: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: false, allowNull: false,
...@@ -26,23 +16,13 @@ module.exports = (sequelize, DataTypes) => { ...@@ -26,23 +16,13 @@ module.exports = (sequelize, DataTypes) => {
end_time: { end_time: {
type: DataTypes.DATE, type: DataTypes.DATE,
allowNull: false, allowNull: false,
validate: {
isAfterStart(value) {
if (value <= this.start_time) {
throw new Error('end_time은 start_time 이후여야 합니다.');
}
},
},
}, },
}, { }, {
tableName: 'Schedules', tableName: 'Schedules',
timestamps: false, timestamps: false,
indexes: [
{
fields: ['user_id'],
},
],
}); });
return Schedule; Schedule.belongsTo(User, { foreignKey: 'user_id', as: 'user' });
}; User.hasMany(Schedule, { foreignKey: 'user_id', as: 'schedules' });
module.exports = Schedule;
// models/User.js // models/User.js
module.exports = (sequelize, DataTypes) => {
const { DataTypes } = require('sequelize');
const sequelize = require('../config/sequelize'); // sequelize 인스턴스 경로에 맞게 수정하세요.
const User = sequelize.define('User', { const User = sequelize.define('User', {
id: {
type: DataTypes.BIGINT,
primaryKey: true,
autoIncrement: true,
},
name: { name: {
type: DataTypes.STRING, type: DataTypes.STRING, // VARCHAR
allowNull: false, allowNull: false,
}, },
email: { email: {
type: DataTypes.STRING, type: DataTypes.STRING, // VARCHAR
allowNull: false, allowNull: false,
unique: true, unique: true,
validate: { validate: {
isEmail: true, // 이메일 형식 검증 isEmail: true,
},
},
invite_code: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4, // 자동으로 UUID 생성
allowNull: false,
unique: true,
},
created_at: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
}, },
// updated_at 추가 (필요 시)
updated_at: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
}, },
}, { }, {
tableName: 'Users', tableName: 'Users',
timestamps: false, // created_at과 updated_at을 수동으로 관리 timestamps: true, // createdAt과 updatedAt 자동 관리
}); });
return User; module.exports = User;
};
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
"version": "1.0.0", "version": "1.0.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"connect-flash": "^0.1.1",
"cookie-parser": "^1.4.7", "cookie-parser": "^1.4.7",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
"express": "^4.21.1", "express": "^4.21.1",
...@@ -17,6 +18,8 @@ ...@@ -17,6 +18,8 @@
"morgan": "^1.10.0", "morgan": "^1.10.0",
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.1",
"mysql2": "^3.11.4", "mysql2": "^3.11.4",
"passport": "^0.7.0",
"passport-google-oauth20": "^2.0.0",
"sequelize": "^6.37.5", "sequelize": "^6.37.5",
"sequelize-cli": "^6.6.2" "sequelize-cli": "^6.6.2"
}, },
...@@ -207,6 +210,15 @@ ...@@ -207,6 +210,15 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/base64url": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz",
"integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==",
"license": "MIT",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/basic-auth": { "node_modules/basic-auth": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
...@@ -528,6 +540,14 @@ ...@@ -528,6 +540,14 @@
"proto-list": "~1.2.1" "proto-list": "~1.2.1"
} }
}, },
"node_modules/connect-flash": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/connect-flash/-/connect-flash-0.1.1.tgz",
"integrity": "sha512-2rcfELQt/ZMP+SM/pG8PyhJRaLKp+6Hk2IUBNkEit09X+vwn3QsAL3ZbYtxUn7NVPzbMTSLRDhqe0B/eh30RYA==",
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/content-disposition": { "node_modules/content-disposition": {
"version": "0.5.4", "version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
...@@ -1971,6 +1991,12 @@ ...@@ -1971,6 +1991,12 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/oauth": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/oauth/-/oauth-0.10.0.tgz",
"integrity": "sha512-1orQ9MT1vHFGQxhuy7E/0gECD3fd2fCC+PIX+/jgmU/gI3EpRocXtmtvxCO5x3WZ443FLTLFWNDjl5MPJf9u+Q==",
"license": "MIT"
},
"node_modules/object-assign": { "node_modules/object-assign": {
"version": "4.1.1", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
...@@ -2028,6 +2054,64 @@ ...@@ -2028,6 +2054,64 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/passport": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz",
"integrity": "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==",
"license": "MIT",
"dependencies": {
"passport-strategy": "1.x.x",
"pause": "0.0.1",
"utils-merge": "^1.0.1"
},
"engines": {
"node": ">= 0.4.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/jaredhanson"
}
},
"node_modules/passport-google-oauth20": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/passport-google-oauth20/-/passport-google-oauth20-2.0.0.tgz",
"integrity": "sha512-KSk6IJ15RoxuGq7D1UKK/8qKhNfzbLeLrG3gkLZ7p4A6DBCcv7xpyQwuXtWdpyR0+E0mwkpjY1VfPOhxQrKzdQ==",
"license": "MIT",
"dependencies": {
"passport-oauth2": "1.x.x"
},
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/passport-oauth2": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.8.0.tgz",
"integrity": "sha512-cjsQbOrXIDE4P8nNb3FQRCCmJJ/utnFKEz2NX209f7KOHPoX18gF7gBzBbLLsj2/je4KrgiwLLGjf0lm9rtTBA==",
"license": "MIT",
"dependencies": {
"base64url": "3.x.x",
"oauth": "0.10.x",
"passport-strategy": "1.x.x",
"uid2": "0.0.x",
"utils-merge": "1.x.x"
},
"engines": {
"node": ">= 0.4.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/jaredhanson"
}
},
"node_modules/passport-strategy": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
"integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==",
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/path-key": { "node_modules/path-key": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
...@@ -2071,6 +2155,11 @@ ...@@ -2071,6 +2155,11 @@
"integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/pause": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
"integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg=="
},
"node_modules/pg-connection-string": { "node_modules/pg-connection-string": {
"version": "2.7.0", "version": "2.7.0",
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.7.0.tgz", "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.7.0.tgz",
...@@ -2822,6 +2911,12 @@ ...@@ -2822,6 +2911,12 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/uid2": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.4.tgz",
"integrity": "sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA==",
"license": "MIT"
},
"node_modules/umzug": { "node_modules/umzug": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/umzug/-/umzug-2.3.0.tgz", "resolved": "https://registry.npmjs.org/umzug/-/umzug-2.3.0.tgz",
......
{ {
"name": "webback", "name": "webback",
"version": "1.0.0", "version": "1.0.0",
"main": "index.js", "main": "app.js",
"scripts": { "scripts": {
"start": "nodemon app",
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"repository": { "repository": {
...@@ -13,6 +14,7 @@ ...@@ -13,6 +14,7 @@
"license": "ISC", "license": "ISC",
"description": "", "description": "",
"dependencies": { "dependencies": {
"connect-flash": "^0.1.1",
"cookie-parser": "^1.4.7", "cookie-parser": "^1.4.7",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
"express": "^4.21.1", "express": "^4.21.1",
...@@ -21,6 +23,8 @@ ...@@ -21,6 +23,8 @@
"morgan": "^1.10.0", "morgan": "^1.10.0",
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.1",
"mysql2": "^3.11.4", "mysql2": "^3.11.4",
"passport": "^0.7.0",
"passport-google-oauth20": "^2.0.0",
"sequelize": "^6.37.5", "sequelize": "^6.37.5",
"sequelize-cli": "^6.6.2" "sequelize-cli": "^6.6.2"
}, },
......
// passport/googleStrategy.js
const { Strategy: GoogleStrategy } = require('passport-google-oauth20');
const User = require('../models/User');
module.exports = new GoogleStrategy(
{
clientID: process.env.GOOGLE_CLIENT_ID, // .env 파일에 설정
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: process.env.CALLBACK_URL,
},
async (accessToken, refreshToken, profile, done) => {
try {
// 프로필에서 사용자 정보 추출
const email = profile.emails[0].value;
const name = profile.displayName;
// 데이터베이스에서 사용자 찾거나 생성
let user = await User.findOne({ where: { email } });
if (!user) {
user = await User.create({ email, name });
}
return done(null, user);
} catch (err) {
return done(err);
}
}
);
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment