Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
students
eue
Commits
7b6f5abb
Commit
7b6f5abb
authored
Jul 28, 2021
by
KangMin An
Browse files
Create & Update: 환경 변수와 서버 상태 전달을 위한 변수들 관리.
parent
7d2a0a29
Changes
9
Show whitespace changes
Inline
Side-by-side
server/.gitignore
View file @
7b6f5abb
...
@@ -4,6 +4,7 @@ package-lock.json
...
@@ -4,6 +4,7 @@ package-lock.json
# Project Environments
# Project Environments
.env
.env
config/config.js
# Project Data
# Project Data
/data
/data
...
...
server/config/config_public.js
0 → 100644
View file @
7b6f5abb
/*
### Configurations File.
- 해당 파일은 공개용으로 작성한 것 입니다. 동일 디렉토리 상에서 config.js를 생성해 사용합니다.
- 환경 변수들을 관리하는 파일입니다.
- 개발 환경에 맞게 값들을 변경하여 사용합니다.
*/
// # Server Envs
const
PROTOCOL
=
"
http
"
;
const
HOST
=
"
localhost
"
;
const
PORT
=
4500
;
// # DB Info.
const
DB_USER
=
"
postgres
"
;
const
DB_PASSWORD
=
"
YOUR_PostgreSQL_PASSWORD
"
;
const
DB_HOST
=
"
localhost
"
;
const
DB_PORT
=
"
5432
"
;
const
DB_DATABASE
=
"
YOUR_DB_NAME
"
;
// # API.
// ## OpenWeatherMap
const
OPENWEATHERMAP_API_KEY
=
"
YOUR_OpenWeatherMap_API_KEY
"
;
// # Nodemailer.
const
NODEMAILER_SERVICE
=
"
gmail
"
;
const
NODEMAILER_USER
=
"
YOUR_MAIL_ADDRESS
"
;
const
NODEMAILER_GAMIL_CLIENT_ID
=
"
YOUR_API_CLIENT_ID
"
;
const
NODEMAILER_GMAIL_CLIENT_PASSWORD
=
"
YOUR_API_CLIENT_PASSWORD
"
;
const
NODEMAILER_GMAIL_REFRESH_TOKEN
=
"
YOUR_GMAIL_REFRESH_TOKEN
"
;
// # Secret Key.
const
AUTH_MAIL_SECRETKEY
=
"
YOUR_MAIL_SECRETKEY
"
;
const
AUTH_ACCESS_TOKEN_SECRETKEY
=
"
YOUR_ACCESS_TOKEN_SECRETKEY
"
;
const
envs
=
{
server
:
{
protocol
:
PROTOCOL
,
host
:
HOST
,
port
:
PORT
,
},
db
:
{
user
:
DB_USER
,
password
:
DB_PASSWORD
,
host
:
DB_HOST
,
port
:
DB_PORT
,
database
:
DB_DATABASE
,
},
api
:
{
openweathermap
:
{
api_key
:
OPENWEATHERMAP_API_KEY
,
},
nodemailer
:
{
service
:
NODEMAILER_SERVICE
,
user
:
NODEMAILER_USER
,
gmail_client_id
:
NODEMAILER_GAMIL_CLIENT_ID
,
gmail_client_passowrd
:
NODEMAILER_GMAIL_CLIENT_PASSWORD
,
gmail_refresh_token
:
NODEMAILER_GMAIL_REFRESH_TOKEN
,
},
},
secretKey
:
{
mail
:
AUTH_MAIL_SECRETKEY
,
access_token
:
AUTH_ACCESS_TOKEN_SECRETKEY
,
},
};
export
default
envs
;
server/src/controllers/dataController.js
View file @
7b6f5abb
import
db
from
"
../db/index
"
;
import
db
from
"
../db/index
"
;
import
dot
env
from
"
dotenv
"
;
import
env
s
from
"
../../config/config
"
;
import
fetch
from
"
node-fetch
"
;
import
fetch
from
"
node-fetch
"
;
import
jwt
from
"
jsonwebtoken
"
;
import
jwt
from
"
jsonwebtoken
"
;
import
{
serverMSG
,
statusCode
}
from
"
../serverinfo
"
;
import
server_status
from
"
../server_status
"
;
dotenv
.
config
();
// 외부 수집기로 부터 들어온 정보 처리
// 외부 수집기로 부터 들어온 정보 처리
const
handleOutData
=
async
(
locCode
,
date
,
lat
,
lng
)
=>
{
const
handleOutData
=
async
(
locCode
,
date
,
lat
,
lng
)
=>
{
// OpenWeatherAPI로 부터 지역의 날씨 정보획득을 위해 지역의 경도와 위도, API Key, 단위 기준 metric 전달
// OpenWeatherAPI로 부터 지역의 날씨 정보획득을 위해 지역의 경도와 위도, API Key, 단위 기준 metric 전달
const
response
=
await
fetch
(
const
response
=
await
fetch
(
`https://api.openweathermap.org/data/2.5/weather?lat=
${
lat
}
&lon=
${
lng
}
&appid=
${
process
.
env
.
OPENWEATHERMAP_API_KEY
}
&units=metric`
`https://api.openweathermap.org/data/2.5/weather?lat=
${
lat
}
&lon=
${
lng
}
&appid=
${
envs
.
api
.
openweathermap
.
api_key
}
&units=metric`
);
);
const
json
=
await
response
.
json
();
const
json
=
await
response
.
json
();
...
@@ -65,8 +63,8 @@ export const getDataInput = (req, res) => {
...
@@ -65,8 +63,8 @@ export const getDataInput = (req, res) => {
`Outside[
${
locCode
}
] Data(date:
${
trans_date
}
/ lat:
${
lat
}
/ lng:
${
lng
}
) Input.`
`Outside[
${
locCode
}
] Data(date:
${
trans_date
}
/ lat:
${
lat
}
/ lng:
${
lng
}
) Input.`
);
);
handleOutData
(
locCode
,
trans_date
,
lat
,
lng
);
handleOutData
(
locCode
,
trans_date
,
lat
,
lng
);
res
.
status
(
status
C
ode
.
ok
).
send
({
res
.
status
(
server_
status
.
c
ode
.
ok
).
send
({
msg
:
server
MSG
.
server_
ok
,
msg
:
server
_status
.
msg
.
ok
,
content
:
`Outside[
${
locCode
}
] data Input.`
,
content
:
`Outside[
${
locCode
}
] data Input.`
,
});
});
}
else
{
}
else
{
...
@@ -83,10 +81,10 @@ export const getDataInput = (req, res) => {
...
@@ -83,10 +81,10 @@ export const getDataInput = (req, res) => {
handleInData
(
email
,
trans_date
,
temp
,
humi
,
lights
);
handleInData
(
email
,
trans_date
,
temp
,
humi
,
lights
);
}
}
res
.
status
(
status
C
ode
.
ok
).
send
(
server
MSG
.
server_
ok
);
res
.
status
(
server_
status
.
c
ode
.
ok
).
send
(
server
_status
.
msg
.
ok
);
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
log
(
error
);
console
.
log
(
error
);
res
.
status
(
status
C
ode
.
err
).
send
(
server
MSG
.
server_
err
);
res
.
status
(
server_
status
.
c
ode
.
err
).
send
(
server
_status
.
msg
.
err
);
}
}
};
};
...
@@ -103,15 +101,17 @@ export const getUserWeatherData = (req, res) => {
...
@@ -103,15 +101,17 @@ export const getUserWeatherData = (req, res) => {
logging
:
false
,
logging
:
false
,
});
});
res
.
status
(
statusCode
.
ok
).
json
({
msg
:
serverMSG
.
server_ok
,
content
:
result
});
res
.
status
(
server_status
.
code
.
ok
)
.
json
({
msg
:
server_status
.
msg
.
ok
,
content
:
result
});
};
};
// 실외 날씨 데이터 요청 처리
// 실외 날씨 데이터 요청 처리
export
const
getOutWeatherData
=
(
req
,
res
)
=>
{
export
const
getOutWeatherData
=
(
req
,
res
)
=>
{
// 실외 지역 번호를 통해 날씨 데이터 전송.
// 실외 지역 번호를 통해 날씨 데이터 전송.
res
res
.
status
(
status
C
ode
.
ok
)
.
status
(
server_
status
.
c
ode
.
ok
)
.
json
({
msg
:
server
MSG
.
server_
ok
,
content
:
"
Outside Weather Data
"
});
.
json
({
msg
:
server
_status
.
msg
.
ok
,
content
:
"
Outside Weather Data
"
});
};
};
// 지역 코드 요청 처리
// 지역 코드 요청 처리
...
@@ -147,7 +147,7 @@ export const getLocCode = async (req, res) => {
...
@@ -147,7 +147,7 @@ export const getLocCode = async (req, res) => {
sgg_emd
.
push
(
temp
);
sgg_emd
.
push
(
temp
);
});
});
res
.
status
(
status
C
ode
.
ok
).
json
({
res
.
status
(
server_
status
.
c
ode
.
ok
).
json
({
locCodes
:
{
locCodes
:
{
DOE
:
does
,
DOE
:
does
,
SGG
:
doe_sgg
,
SGG
:
doe_sgg
,
...
...
server/src/controllers/userController.js
View file @
7b6f5abb
import
db
from
"
../db/index
"
;
import
db
from
"
../db/index
"
;
import
dot
env
from
"
dotenv
"
;
import
env
s
from
"
../../config/config
"
;
import
jwt
from
"
jsonwebtoken
"
;
import
jwt
from
"
jsonwebtoken
"
;
import
nodemailer
from
"
nodemailer
"
;
import
nodemailer
from
"
nodemailer
"
;
import
{
server
MSG
,
status
Code
}
from
"
../server
info
"
;
import
server
_
status
from
"
../server
_status
"
;
import
routes
from
"
../routes
"
;
import
routes
from
"
../routes
"
;
dotenv
.
config
();
// 메일 전송 처리
// 메일 전송 처리
const
postMail
=
async
(
email
,
token
)
=>
{
const
postMail
=
async
(
email
,
token
)
=>
{
const
transporter
=
nodemailer
.
createTransport
({
const
transporter
=
nodemailer
.
createTransport
({
service
:
process
.
env
.
NODEMAILER_SERVICE
,
service
:
envs
.
api
.
nodemailer
.
service
,
auth
:
{
auth
:
{
type
:
"
OAuth2
"
,
type
:
"
OAuth2
"
,
user
:
process
.
env
.
NODEMAILER_USER
,
user
:
envs
.
api
.
nodemailer
.
user
,
clientId
:
process
.
env
.
NODEMAILER_GAMIL_CLIENT_ID
,
clientId
:
envs
.
api
.
nodemailer
.
gmail_client_id
,
clientSecret
:
process
.
env
.
NODEMAILER_GMAIL_CLIENT_PASSWORD
,
clientSecret
:
envs
.
api
.
nodemailer
.
gmail_client_secret
,
refreshToken
:
process
.
env
.
NODEMAILER_GMAIL_REFRESH_TOKEN
,
refreshToken
:
envs
.
api
.
nodemailer
.
gmail_refresh_token
,
},
},
tls
:
{
tls
:
{
rejectUnauthorized
:
false
,
rejectUnauthorized
:
false
,
...
@@ -24,14 +22,14 @@ const postMail = async (email, token) => {
...
@@ -24,14 +22,14 @@ const postMail = async (email, token) => {
});
});
const
mailOptions
=
{
const
mailOptions
=
{
from
:
`EUE Auth Supply <
${
process
.
env
.
NODEMAILER_USER
}
>`
,
from
:
`EUE Auth Supply <
${
envs
.
api
.
nodemailer
.
user
}
>`
,
to
:
email
,
to
:
email
,
subject
:
"
EUE 사용자 계정 확인용 메일.
"
,
subject
:
"
EUE 사용자 계정 확인용 메일.
"
,
html
:
`<a href="
${
process
.
env
.
PROTOCOL
}
://
${
process
.
env
.
HOST
}
:
${
html
:
`<a href="
${
envs
.
server
.
protocol
}
://
${
envs
.
server
.
host
}
:
${
process
.
env
.
PORT
envs
.
server
.
port
}${
routes
.
base
+
routes
.
confirm
}
?token=
${
token
}
">
${
}${
routes
.
base
+
routes
.
confirm
}
?token=
${
token
}
">
${
process
.
env
.
PROTOCOL
envs
.
server
.
protocol
}
://
${
process
.
env
.
HOST
}
:
${
process
.
env
.
PORT
}${
}
://
${
envs
.
server
.
host
}
:
${
envs
.
server
.
port
}${
routes
.
base
+
routes
.
confirm
routes
.
base
+
routes
.
confirm
}
?token=
${
token
}
</a>`
,
}
?token=
${
token
}
</a>`
,
};
};
...
@@ -72,8 +70,8 @@ export const postSignup = async (req, res) => {
...
@@ -72,8 +70,8 @@ export const postSignup = async (req, res) => {
});
});
if
(
result
.
length
!=
0
)
{
if
(
result
.
length
!=
0
)
{
res
.
status
(
status
C
ode
.
err
).
json
({
res
.
status
(
server_
status
.
c
ode
.
err
).
json
({
msg
:
server
MSG
.
server_
err
,
msg
:
server
_status
.
msg
.
err
,
content
:
"
You are aleady registered
"
,
content
:
"
You are aleady registered
"
,
});
});
}
else
{
}
else
{
...
@@ -100,7 +98,7 @@ export const postLogin = async (req, res) => {
...
@@ -100,7 +98,7 @@ export const postLogin = async (req, res) => {
{
{
email
:
email
,
email
:
email
,
},
},
process
.
env
.
AUTH_MAIL_SECRETKEY
,
envs
.
secretKey
.
mail
,
{
{
expiresIn
:
10
*
60
,
expiresIn
:
10
*
60
,
issuer
:
"
eue.com
"
,
issuer
:
"
eue.com
"
,
...
@@ -112,11 +110,11 @@ export const postLogin = async (req, res) => {
...
@@ -112,11 +110,11 @@ export const postLogin = async (req, res) => {
postMail
(
email
,
mail_token
);
postMail
(
email
,
mail_token
);
res
res
.
status
(
status
C
ode
.
ok
)
.
status
(
server_
status
.
c
ode
.
ok
)
.
json
({
msg
:
server
MSG
.
server_
ok
,
content
:
"
Send Mail Successfully.
"
});
.
json
({
msg
:
server
_status
.
msg
.
ok
,
content
:
"
Send Mail Successfully.
"
});
}
else
{
}
else
{
res
.
status
(
status
C
ode
.
err
).
json
({
res
.
status
(
server_
status
.
c
ode
.
err
).
json
({
msg
:
server
MSG
.
server_
err
,
msg
:
server
_status
.
msg
.
err
,
content
:
"
You are not one of our user yet.
"
,
content
:
"
You are not one of our user yet.
"
,
});
});
}
}
...
@@ -129,7 +127,7 @@ export const getConfirm = async (req, res) => {
...
@@ -129,7 +127,7 @@ export const getConfirm = async (req, res) => {
}
=
req
;
}
=
req
;
try
{
try
{
const
decoded
=
jwt
.
verify
(
token
,
process
.
env
.
AUTH_MAIL_SECRETKEY
);
// return payload.
const
decoded
=
jwt
.
verify
(
token
,
envs
.
secretKey
.
mail
);
// return payload.
const
result
=
await
db
.
User
.
findAll
({
const
result
=
await
db
.
User
.
findAll
({
where
:
{
email
:
decoded
.
email
},
where
:
{
email
:
decoded
.
email
},
...
@@ -141,17 +139,20 @@ export const getConfirm = async (req, res) => {
...
@@ -141,17 +139,20 @@ export const getConfirm = async (req, res) => {
email
:
user
.
email
,
email
:
user
.
email
,
};
};
const
accessT
=
jwt
.
sign
(
payload
,
process
.
env
.
AUTH_ACCESS_SECRETKEY
,
{
const
accessT
=
jwt
.
sign
(
payload
,
envs
.
secretKey
.
access_token
,
{
expiresIn
:
"
14d
"
,
expiresIn
:
"
14d
"
,
issuer
:
"
eue.com
"
,
issuer
:
"
eue.com
"
,
subject
:
"
userInfo
"
,
subject
:
"
userInfo
"
,
});
});
res
.
status
(
statusCode
.
ok
).
cookie
(
"
acs_token
"
,
accessT
).
redirect
(
"
/api
"
);
res
.
status
(
server_status
.
code
.
ok
)
.
cookie
(
"
acs_token
"
,
accessT
)
.
redirect
(
"
/api
"
);
}
catch
(
err
)
{
}
catch
(
err
)
{
res
res
.
status
(
status
C
ode
.
err
)
.
status
(
server_
status
.
c
ode
.
err
)
.
json
({
msg
:
server
MSG
.
server_
err
,
content
:
`
${
err
}
`
});
.
json
({
msg
:
server
_status
.
msg
.
err
,
content
:
`
${
err
}
`
});
}
}
};
};
...
@@ -165,7 +166,7 @@ export const getUserInfo = async (req, res) => {
...
@@ -165,7 +166,7 @@ export const getUserInfo = async (req, res) => {
const
result
=
await
db
.
User
.
findAll
({
where
:
{
email
:
decoded
.
email
}
});
const
result
=
await
db
.
User
.
findAll
({
where
:
{
email
:
decoded
.
email
}
});
res
.
status
(
status
C
ode
.
ok
).
json
({
user_info
:
result
});
res
.
status
(
server_
status
.
c
ode
.
ok
).
json
({
user_info
:
result
});
};
};
// 사용자 정보 수정 요청 처리
// 사용자 정보 수정 요청 처리
...
@@ -177,8 +178,8 @@ export const postEditProfile = (req, res) => {
...
@@ -177,8 +178,8 @@ export const postEditProfile = (req, res) => {
// 수신한 변경 내용들을 통해 DB Update.
// 수신한 변경 내용들을 통해 DB Update.
res
res
.
status
(
status
C
ode
.
ok
)
.
status
(
server_
status
.
c
ode
.
ok
)
.
json
({
msg
:
server
MSG
.
server_
ok
,
content
:
"
Server OK
"
});
.
json
({
msg
:
server
_status
.
msg
.
ok
,
content
:
"
Server OK
"
});
};
};
// 사용자의 지역 코드 설정 처리
// 사용자의 지역 코드 설정 처리
...
@@ -201,14 +202,14 @@ export const postSetLoccode = async (req, res) => {
...
@@ -201,14 +202,14 @@ export const postSetLoccode = async (req, res) => {
loc_code
:
loccode
,
loc_code
:
loccode
,
};
};
const
accessT
=
jwt
.
sign
(
payload
,
process
.
env
.
AUTH_ACCESS_SECRETKEY
,
{
const
accessT
=
jwt
.
sign
(
payload
,
envs
.
secretKey
.
access_token
,
{
expiresIn
:
"
14d
"
,
expiresIn
:
"
14d
"
,
issuer
:
"
eue.com
"
,
issuer
:
"
eue.com
"
,
subject
:
"
userInfo
"
,
subject
:
"
userInfo
"
,
});
});
res
res
.
status
(
status
C
ode
.
ok
)
.
status
(
server_
status
.
c
ode
.
ok
)
.
cookie
(
"
acs_token
"
,
accessT
)
.
cookie
(
"
acs_token
"
,
accessT
)
.
json
({
msg
:
server
MSG
.
server_
ok
,
content
:
"
Successfully Set Loccode
"
});
.
json
({
msg
:
server
_status
.
msg
.
ok
,
content
:
"
Successfully Set Loccode
"
});
};
};
server/src/db/index.js
View file @
7b6f5abb
import
Sequelize
from
"
sequelize
"
;
import
Sequelize
from
"
sequelize
"
;
import
dot
env
from
"
dotenv
"
;
import
env
s
from
"
../../config/config
"
;
import
Doe
from
"
../models/doe
"
;
import
Doe
from
"
../models/doe
"
;
import
Sgg
from
"
../models/sgg
"
;
import
Sgg
from
"
../models/sgg
"
;
import
Emd
from
"
../models/emd
"
;
import
Emd
from
"
../models/emd
"
;
...
@@ -7,19 +7,16 @@ import User from "../models/user";
...
@@ -7,19 +7,16 @@ import User from "../models/user";
import
Weather_in
from
"
../models/weather_in
"
;
import
Weather_in
from
"
../models/weather_in
"
;
import
Weather_out
from
"
../models/weather_out
"
;
import
Weather_out
from
"
../models/weather_out
"
;
dotenv
.
config
();
const
envs
=
process
.
env
;
// DB의 정보를 모두 담고 있는 객체 생성
// DB의 정보를 모두 담고 있는 객체 생성
const
db
=
{};
const
db
=
{};
// PostgreSQL과 연결된 Sequelize 객체 생성
// PostgreSQL과 연결된 Sequelize 객체 생성
const
sequelize
=
new
Sequelize
(
const
sequelize
=
new
Sequelize
(
envs
.
DB_DATABASE
,
envs
.
db
.
database
,
envs
.
DB_USER
,
envs
.
db
.
user
,
envs
.
DB_PASSWORD
,
envs
.
db
.
password
,
{
{
host
:
envs
.
DB_HOST
,
host
:
envs
.
db
.
host
,
dialect
:
"
postgres
"
,
dialect
:
"
postgres
"
,
}
}
);
);
...
...
server/src/init.js
View file @
7b6f5abb
import
app
from
"
./app
"
;
import
app
from
"
./app
"
;
import
dot
env
from
"
dotenv
"
;
import
env
s
from
"
../config/config
"
;
import
"
./schedules
"
;
// 매일 자정 데이터 처리
import
"
./schedules
"
;
// 매일 자정 데이터 처리
import
db
from
"
./db/index
"
;
import
db
from
"
./db/index
"
;
import
setLocTables
from
"
./db/locationSetting
"
;
import
setLocTables
from
"
./db/locationSetting
"
;
dotenv
.
config
();
const
PORT
=
envs
.
server
.
port
||
4500
;
const
PORT
=
process
.
env
.
PORT
||
4500
;
const
handleListening
=
()
=>
{
const
handleListening
=
()
=>
{
console
.
log
(
`✅ Listening on : http://localhost:
${
PORT
}
`
);
console
.
log
(
`✅ Listening on : http://localhost:
${
PORT
}
`
);
...
...
server/src/middlewares.js
View file @
7b6f5abb
import
routes
from
"
./routes
"
;
import
routes
from
"
./routes
"
;
import
jwt
from
"
jsonwebtoken
"
;
import
jwt
from
"
jsonwebtoken
"
;
import
envs
from
"
../config/config
"
;
/*
/*
# localmiddleware
# localmiddleware
...
@@ -20,7 +21,7 @@ export const onlyPrivate = (req, res, next) => {
...
@@ -20,7 +21,7 @@ export const onlyPrivate = (req, res, next) => {
}
=
req
;
}
=
req
;
try
{
try
{
const
acs_decode
=
jwt
.
verify
(
acs_token
,
process
.
env
.
AUTH_ACCESS_SECRETKEY
);
const
acs_decode
=
jwt
.
verify
(
acs_token
,
envs
.
secretKey
.
access_token
);
next
();
next
();
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
log
(
error
);
console
.
log
(
error
);
...
...
server/src/server_status.js
0 → 100644
View file @
7b6f5abb
const
SERVER_MSG_OK
=
"
Server OK.
"
;
const
SERVER_MSG_ERROR
=
"
The server encountered an error.
"
;
const
STATUS_CODE_OK
=
200
;
const
STATUS_CODE_ERROR
=
500
;
const
server_status
=
{
msg
:
{
ok
:
SERVER_MSG_OK
,
err
:
SERVER_MSG_ERROR
,
},
code
:
{
ok
:
STATUS_CODE_OK
,
err
:
STATUS_CODE_ERROR
,
},
};
export
default
server_status
;
server/src/serverinfo.js
deleted
100644 → 0
View file @
7d2a0a29
const
SERVER_OK_MSG
=
"
Server OK.
"
;
const
SERVER_ERROR_MSG
=
"
The server encountered an error.
"
;
const
STATUS_OK_CODE
=
200
;
const
STATUS_ERROR_CODE
=
500
;
export
const
serverMSG
=
{
server_ok
:
SERVER_OK_MSG
,
server_err
:
SERVER_ERROR_MSG
,
};
export
const
statusCode
=
{
ok
:
STATUS_OK_CODE
,
err
:
STATUS_ERROR_CODE
,
};
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment