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
1 change: 1 addition & 0 deletions backend/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.sh text eol=lf
33 changes: 33 additions & 0 deletions backend/controllers/tagController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const Tag = require('../models/tags');

exports.getAllTags = async (req, res) => {
try {
const tags = await Tag.findAll();
res.json(tags);
} catch (err) {
console.error('Error fetching tags:', err);
res.status(500).json({ error: 'Failed to fetch tags' });
}
};

exports.createTag = async (req, res) => {
const { name } = req.body;

// Basic validation
if (!name) {
return res.status(400).json({ error: 'Tag name is required' });
}

try {
const existing = await Tag.findByName(name);
if (existing) {
return res.status(409).json({ error: 'Tag already exists' });
}

const tag = await Tag.create(name);
res.status(201).json(tag);
} catch (err) {
console.error('Error creating tag:', err);
res.status(500).json({ error: 'Failed to create tag' });
}
};
12 changes: 12 additions & 0 deletions backend/db/folders.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-- 開啟 UUID extension(若尚未啟用)
CREATE EXTENSION IF NOT EXISTS "pgcrypto";

-- Create folders table
CREATE TABLE IF NOT EXISTS folders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title VARCHAR(255) NOT NULL,
tag_id UUID NOT NULL,
user_id UUID NOT NULL REFERENCES users(id),
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
18 changes: 1 addition & 17 deletions backend/db/questions.sql
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
-- Create folders table
CREATE TABLE IF NOT EXISTS folders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title VARCHAR(255) NOT NULL,
tag_id UUID NOT NULL,
user_id UUID NOT NULL REFERENCES users(id),
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);


-- Create questions table
CREATE TABLE IF NOT EXISTS questions (
Expand All @@ -22,11 +14,3 @@ CREATE TABLE IF NOT EXISTS questions (
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

-- Create tags table
CREATE TABLE IF NOT EXISTS tags (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(255) NOT NULL,
user_id UUID NOT NULL REFERENCES users(id),
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
11 changes: 11 additions & 0 deletions backend/db/tags.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
-- 開啟 UUID extension(若尚未啟用)
CREATE EXTENSION IF NOT EXISTS "pgcrypto";

-- Create tags table
CREATE TABLE IF NOT EXISTS tags (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(255) NOT NULL,
user_id UUID NOT NULL REFERENCES users(id),
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
14 changes: 14 additions & 0 deletions backend/db/tokens.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
-- 開啟 UUID extension(若尚未啟用)
CREATE EXTENSION IF NOT EXISTS "pgcrypto";

-- 建立 tokens 表格
CREATE TABLE IF NOT EXISTS tokens (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
value TEXT NOT NULL UNIQUE,
expired_at TIMESTAMP NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

-- 外鍵關聯
CONSTRAINT fk_token_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
5 changes: 5 additions & 0 deletions backend/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ app.use((err, req, res, next) => {
});
});

const tagRoutes = require('./routes/tagRoutes');
app.use('/tags', tagRoutes);

const PORT = process.env.PORT || 3000;

app.listen(PORT, '0.0.0.0', (err) => {
Expand All @@ -82,4 +85,6 @@ app.listen(PORT, '0.0.0.0', (err) => {
console.log('- GET /auth/me');
console.log('- GET /api/test');
console.log('- POST /api/question-set');
// console.log('- POST /tags');
console.log('- GET /tags');
});
Empty file added backend/models/folders.js
Empty file.
17 changes: 15 additions & 2 deletions backend/models/questions.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ class QuestionSet {
return result.rows[0];
}

static async findTagByName(name, userId) {
const query = `
SELECT * FROM tags
WHERE name = $1 AND user_id = $2
`;
const result = await db.query(query, [name, userId]);
return result.rows[0] || null;
}

static async createTag(name, userId) {
const query = `
INSERT INTO tags (name, user_id)
Expand Down Expand Up @@ -43,8 +52,12 @@ class QuestionSet {
try {
await client.query('BEGIN');

// Create tag
const tag = await this.createTag(tagName, userId);
// Check if tag already exists
const tag = await this.findTagByName(tagName, userId);
if (!tag) {
// Create tag if not exists
tag = await this.createTag(tagName, userId);
}

// Create folder
const folder = await this.createFolder(folderName, tag.id, userId);
Expand Down
23 changes: 23 additions & 0 deletions backend/models/tags.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const pool = require('../db/db');

const Tag = {
async create(name) {
const result = await pool.query(
'INSERT INTO tags (name) VALUES ($1) RETURNING *',
[name]
);
return result.rows[0];
},

async findAll() {
const result = await pool.query('SELECT * FROM tags ORDER BY created_at DESC');
return result.rows;
},

async findByName(name) {
const result = await pool.query('SELECT * FROM tags WHERE name = $1', [name]);
return result.rows[0];
}
};

module.exports = Tag;
Loading