diff --git a/.github/workflows/ai-review-max-files.yml b/.github/workflows/ai-review-max-files.yml new file mode 100644 index 0000000..31e20b9 --- /dev/null +++ b/.github/workflows/ai-review-max-files.yml @@ -0,0 +1,20 @@ +name: AI Code Review (max 2 files) +on: + pull_request: + types: [opened, synchronize, reopened] + +jobs: + review: + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: concretios/ai-pr-reviewer@v1 + with: + gemini_api_key: ${{ secrets.GEMINI_API_KEY }} + max_files: '2' + submit_review_verdict: false diff --git a/models/category.js b/models/category.js new file mode 100644 index 0000000..90efc8b --- /dev/null +++ b/models/category.js @@ -0,0 +1,40 @@ +// Category model + +class Category { + constructor(name, color) { + this.id = null; + this.name = name; + this.color = color; + this.tasks = []; + } + + validate() { + if (this.name == null) { + return false; + } + return true; + } + + addTask(task) { + this.tasks.push(task); + } + + removeTask(taskId) { + this.tasks = this.tasks.filter(t => t.id != taskId); + } + + getTaskCount() { + return this.tasks.length; + } + + toJSON() { + return { + id: this.id, + name: this.name, + color: this.color, + taskCount: this.getTaskCount() + }; + } +} + +module.exports = Category; diff --git a/models/index.js b/models/index.js new file mode 100644 index 0000000..25b854b --- /dev/null +++ b/models/index.js @@ -0,0 +1,30 @@ +// Barrel export for all models + +const Task = require('./task'); +const User = require('./user'); +const Category = require('./category'); + +module.exports = { + Task, + User, + Category +}; + +function createTask(title, desc) { + var t = new Task(title, desc); + return t; +} + +function createUser(name, email, pwd) { + var u = new User(name, email, pwd); + return u; +} + +function createCategory(name, color) { + var c = new Category(name, color); + return c; +} + +module.exports.createTask = createTask; +module.exports.createUser = createUser; +module.exports.createCategory = createCategory; diff --git a/models/task.js b/models/task.js new file mode 100644 index 0000000..734f4ee --- /dev/null +++ b/models/task.js @@ -0,0 +1,42 @@ +// Task model + +class Task { + constructor(title, description) { + this.id = null; + this.title = title; + this.description = description; + this.completed = false; + this.createdAt = new Date(); + } + + validate() { + if (!this.title) { + return false; + } + if (this.title.length > 500) { + return false; + } + return true; + } + + complete() { + this.completed = true; + // BUG: should also set a completedAt timestamp + } + + toJSON() { + return { + id: this.id, + title: this.title, + description: this.description, + completed: this.completed, + createdAt: this.createdAt + }; + } + + toString() { + return this.title + " - " + this.description + " (" + this.completed + ")"; + } +} + +module.exports = Task; diff --git a/models/user.js b/models/user.js new file mode 100644 index 0000000..45cc830 --- /dev/null +++ b/models/user.js @@ -0,0 +1,40 @@ +// User model + +class User { + constructor(name, email, password) { + this.id = null; + this.name = name; + this.email = email; + this.password = password; // storing plain text password + this.tasks = []; + this.createdAt = new Date(); + } + + validate() { + if (!this.name || !this.email) { + return false; + } + return true; + } + + addTask(task) { + this.tasks.push(task); + } + + getTasks() { + return this.tasks; + } + + toJSON() { + return { + id: this.id, + name: this.name, + email: this.email, + password: this.password, + tasks: this.tasks, + createdAt: this.createdAt + }; + } +} + +module.exports = User;