Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
DB_ENDPOINT=""
DB_USERNAME=""
DB_PASSWORD=""
DB_BUCKET=""
71 changes: 38 additions & 33 deletions api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,39 +13,44 @@ const log = Logger.child({
});

const main = async () => {

await setupOttoman();

app.use(cors(corsOptions));
app.use(express.json()); // middleware to parse json
app.use(cookieParser());

// static route
app.use('/', express.static(path.join(__dirname, '/public')));
app.use('/', require('../routes/root'));

// user routes - for testing
app.use('/test', require('../routes/testRoutes'));

// user routes - for /api/users and /api/user
app.use('/api', require('../routes/userRoutes'));

// user routes - for profiles
app.use('/api/profiles', require('../routes/profileRoutes'));

// article routes
app.use('/api/articles', require('../routes/articleRoutes'));

// tag route
app.use('/api/tags', require('../routes/tagRoutes'));

// comment routes
app.use('/api/articles', require('../routes/commentRoutes'));

app.listen(PORT, () => {
log.info(`Server running on port ${PORT}`);
});
console.log("Starting Ottoman setup...");
await setupOttoman();
console.log("Ottoman setup complete.");

console.log("Setting up middleware...");
app.use(cors(corsOptions));
app.use(express.json()); // middleware to parse json
app.use(cookieParser());

// static route
app.use('/', express.static(path.join(__dirname, '/public')));
console.log("Static routes set up.");

// user routes - for testing
app.use('/test', require('../routes/testRoutes'));
console.log("Test routes set up.");

// user routes - for /api/users and /api/user
app.use('/api', require('../routes/userRoutes'));
console.log("User routes set up.");

// user routes - for profiles
app.use('/api/profiles', require('../routes/profileRoutes'));
console.log("Profile routes set up.");

// article routes
app.use('/api/articles', require('../routes/articleRoutes'));
console.log("Article routes set up.");

// comment routes
app.use('/api/articles/:articleId/comments', require('../routes/commentRoutes'));
console.log("Comment routes set up.");

app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
};

main();

module.exports = app;
7 changes: 3 additions & 4 deletions config/dbConnect.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ const setupOttoman = async function(){
// TODO: Fix global plugin registration
await registerGlobalPlugin((schema) => {
schema.pre('save', function (doc) {
log.info("SAAAAAVE");
console.log("SAAAAAVE");
});
});

let ottoman = getDefaultInstance();
if (!ottoman) {
// if not exist default one, then create
ottoman = new Ottoman();
ottoman = new Ottoman({ensureIndexes: true});
};

const endpoint = process.env.DB_ENDPOINT || "couchbase://localhost";
Expand All @@ -44,8 +44,7 @@ const setupOttoman = async function(){
const Article = model('Article', articleSchema, { scopeName: scope });

await ottoman.start();
log.info('Connected to Couchbase');
console.log('Connected to Couchbase');
}

module.exports = {setupOttoman, User, Comment, Article}

2 changes: 1 addition & 1 deletion controllers/articlesController.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ const listArticles = asyncHandler(async (req, res) => {
if (req.query.favorited) {
const favoriter = await User.findOne({username: req.query.favorited}).catch(e => log.debug(e, "User not Found"))
if (favoriter) {
query.id = {$in: favoriter.favouriteArticles}
query.id = {$in: favoriter.favoritedArticles}
}
}
const {rows : filteredArticles} = await Article.find(query,{limit: Number(limit), skip: Number(offset), sort: {createdAt: 'DESC'} });
Expand Down
117 changes: 72 additions & 45 deletions controllers/usersController.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,49 @@
const asyncHandler = require('express-async-handler');
const bcrypt = require('bcrypt');
const {getModel} = require('ottoman');
const User = getModel('User');
const { PropertyRequiredError} = require("../api/errors");
const {Logger} = require('../config/logger');
const { getModel } = require('ottoman');
const User = getModel('User'); // Ensure this is correctly initialized
const { PropertyRequiredError } = require("../api/errors");
const { Logger } = require('../config/logger');
const log = Logger.child({
namespace: 'UsersController',
});


// @desc registration for a user
// @route POST /api/users
// @access Public
// @required fields {email, username, password}
// @return User
const registerUser = asyncHandler(async (req, res) => {
console.log("Received request to register user:", req.body);

const { user } = req.body;

// confirm data
if (!user || !user.email || !user.username || !user.password) {
const error = {message: "All fields are required"};
console.log("Validation failed: Missing required fields");
const error = { message: "All fields are required" };
if (!user.email) error["email"] = "";
if (!user.username) error["username"] = "";
if (!user.password) error["password"] = "";
return res.status(400).json(error);
}

// hash password
const hashedPwd = await bcrypt.hash(user.password, 10); // salt rounds
console.log("Hashing password for user:", user.username);
const hashedPwd = await bcrypt.hash(user.password, 10); // Salt rounds

const userObject = {
"username": user.username,
"password": hashedPwd,
"email": user.email
};

console.log("Creating user object in Couchbase:", userObject);

const createdUser = await User.create(userObject).catch(e => {
log.debug(e.name)
log.debug(e.message)
log.debug(e.property)
log.debug(e)
console.log("Error creating user:", e);
log.debug(e.name);
log.debug(e.message);
log.debug(e.property);
log.debug(e);
if (e instanceof PropertyRequiredError) {
const err = {
errors: {
Expand All @@ -47,15 +52,18 @@ const registerUser = asyncHandler(async (req, res) => {
};
if (e.field) {
err[e.field] = e.value;
return res.status(422).json({err});
return res.status(422).json({ err });
}
}
});
if (createdUser) { // user object created

if (createdUser) { // User object created
console.log("User created successfully:", createdUser);
res.status(201).json({
user: createdUser.toUserResponse()
})
});
} else {
console.log("Failed to create user");
res.status(422).json({
errors: {
body: "Unable to register a user",
Expand All @@ -70,18 +78,24 @@ const registerUser = asyncHandler(async (req, res) => {
// @access Private
// @return User
const getCurrentUser = asyncHandler(async (req, res) => {
// After authentication; email and hashsed password was stored in req
console.log("Fetching current user for email:", req.userEmail);

const email = req.userEmail;

const user = await User.findOne({ email }).catch(e => log.debug(e, "Error fetching user"));
const user = await User.findOne({ email }).catch(e => {
console.log("Error fetching user:", e);
log.debug(e, "Error fetching user");
});

if (!user) {
return res.status(404).json({message: "User Not Found"});
console.log("User not found for email:", email);
return res.status(404).json({ message: "User Not Found" });
}

console.log("User found:", user);
res.status(200).json({
user: user.toUserResponse()
})

});
});

// @desc login for a user
Expand All @@ -90,24 +104,36 @@ const getCurrentUser = asyncHandler(async (req, res) => {
// @required fields {email, password}
// @return User
const userLogin = asyncHandler(async (req, res) => {
console.log("Attempting login for user:", req.body.user);

const { user } = req.body;

// confirm data
// Confirm data
if (!user || !user.email || !user.password) {
return res.status(400).json({message: "All fields are required"});
console.log("Login failed: Missing email or password");
return res.status(400).json({ message: "All fields are required" });
}

const loginUser = await User.findOne({ email: user.email }).catch(e => log.debug(e, "Error fetching user"));
const loginUser = await User.findOne({ email: user.email }).catch(e => {
console.log("Error fetching user for login:", e);
log.debug(e, "Error fetching user");
});

if (!loginUser) {
return res.status(404).json({errors: { message: 'User Not Found' }});
console.log("Login failed: User not found for email", user.email);
return res.status(404).json({ errors: { message: 'User Not Found' } });
}

const match = await bcrypt.compare(user.password, loginUser.password);
if (!match) {return res.status(401).json({errors: { message: 'Unauthorized: Wrong password' }})}
if (!match) {
console.log("Login failed: Incorrect password");
return res.status(401).json({ errors: { message: 'Unauthorized: Wrong password' } });
}

console.log("User logged in successfully:", loginUser);
res.status(200).json({
user: loginUser.toUserResponse()
});

});

// @desc update currently logged-in user
Expand All @@ -116,47 +142,48 @@ const userLogin = asyncHandler(async (req, res) => {
// @access Private
// @return User
const updateUser = asyncHandler(async (req, res) => {
console.log("Attempting to update user:", req.body.user);

const { user } = req.body;

// confirm data
// Confirm data
if (!user) {
return res.status(400).json({message: "Required a User object"});
console.log("Update failed: Missing user object");
return res.status(400).json({ message: "Required a User object" });
}

const email = req.userEmail;

const target = await User.findOne({ email }).catch(e => log.debug(e, "Error fetching user"));
const target = await User.findOne({ email }).catch(e => {
console.log("Error fetching user for update:", e);
log.debug(e, "Error fetching user");
});

if (!target) {
return res.status(404).json({message: "User not found"});
}
if (user.email) {
target.email = user.email;
}
if (user.username) {
target.username = user.username;
console.log("Update failed: User not found for email", email);
return res.status(404).json({ message: "User not found" });
}

if (user.email) target.email = user.email;
if (user.username) target.username = user.username;
if (user.password) {
const hashedPwd = await bcrypt.hash(user.password, 10);
target.password = hashedPwd;
}
if (typeof user.image !== 'undefined') {
target.image = user.image;
}
if (typeof user.bio !== 'undefined') {
target.bio = user.bio;
}
if (typeof user.image !== 'undefined') target.image = user.image;
if (typeof user.bio !== 'undefined') target.bio = user.bio;

await target.save();
console.log("User updated successfully:", target);

return res.status(200).json({
user: target.toUserResponse()
});

});

module.exports = {
registerUser,
getCurrentUser,
userLogin,
updateUser
}
};
Loading