1
0

Move everything to models and services (#17)

This commit is contained in:
konrad
2019-03-02 10:25:10 +00:00
committed by Gitea
parent 8559d8bb97
commit 9b0c842ae1
50 changed files with 2165 additions and 1206 deletions

View File

@ -0,0 +1,21 @@
import {defaults, omitBy, isNil} from 'lodash'
export default class AbstractModel {
/**
* The abstract constructor takes an object and merges its data with the default data of this model.
* @param data
*/
constructor(data) {
// Put all data in our model while overriding those with a value of null or undefined with their defaults
defaults(this, omitBy(data, isNil), this.defaults())
}
/**
* Default attributes that define the "empty" state.
* @return {{}}
*/
defaults() {
return {}
}
}

1
src/models/config.js Normal file
View File

@ -0,0 +1 @@
export const URL_PREFIX = '/api/v1' // _without_ slash at the end

111
src/models/list.js Normal file
View File

@ -0,0 +1,111 @@
import AbstractModel from './abstractModel'
import TaskModel from './task'
import UserModel from './user'
export default class ListModel extends AbstractModel {
constructor(data) {
super(data)
// Make all tasks to task models
this.tasks = this.tasks.map(t => {
return new TaskModel(t)
})
this.owner = new UserModel(this.owner)
this.sortTasks()
}
// Default attributes that define the "empty" state.
defaults() {
return {
id: 0,
title: '',
description: '',
owner: UserModel,
tasks: [],
namespaceID: 0,
created: 0,
updated: 0,
}
}
////////
// Helpers
//////
/**
* Sorts all tasks according to their due date
* @returns {this}
*/
sortTasks() {
if (this.tasks === null || this.tasks === []) {
return
}
return this.tasks.sort(function(a,b) {
if (a.done < b.done)
return -1
if (a.done > b.done)
return 1
return 0
})
}
/**
* Adds a task to the task array of this list. Usually only used when creating a new task
* @param task
*/
addTaskToList(task) {
// If it's a subtask, add it to its parent, otherwise append it to the list of tasks
if (task.parentTaskID === 0) {
this.tasks.push(task)
} else {
for (const t in this.tasks) {
if (this.tasks[t].id === task.parentTaskID) {
this.tasks[t].subtasks.push(task)
break
}
}
}
this.sortTasks()
}
/**
* Gets a task by its ID by looping through all tasks.
* @param id
* @returns {TaskModel}
*/
getTaskByID(id) {
// TODO: Binary search?
for (const t in this.tasks) {
if (this.tasks[t].id === parseInt(id)) {
return this.tasks[t]
}
}
return {} // FIXME: This should probably throw something to make it clear to the user noting was found
}
/**
* Loops through all tasks and updates the one with the id it has
* @param task
*/
updateTaskByID(task) {
for (const t in this.tasks) {
if (this.tasks[t].id === task.id) {
this.tasks[t] = task
break
}
if (this.tasks[t].id === task.parentTaskID) {
for (const s in this.tasks[t].subtasks) {
if (this.tasks[t].subtasks[s].id === task.id) {
this.tasks[t].subtasks[s] = task
break
}
}
}
}
this.sortTasks()
}
}

28
src/models/namespace.js Normal file
View File

@ -0,0 +1,28 @@
import AbstractModel from './abstractModel'
import ListModel from './list'
import UserModel from './user'
export default class NamespaceModel extends AbstractModel {
constructor(data) {
super(data)
this.lists = this.lists.map(l => {
return new ListModel(l)
})
this.owner = new UserModel(this.owner)
}
// Default attributes that define the 'empty' state.
defaults() {
return {
id: 0,
name: '',
description: '',
owner: UserModel,
lists: [],
created: 0,
updated: 0,
}
}
}

View File

@ -0,0 +1,17 @@
import AbstractModel from "./abstractModel";
export default class PasswordResetModel extends AbstractModel {
constructor(data) {
super(data)
this.token = localStorage.getItem('passwordResetToken')
}
defaults() {
return {
token: '',
new_password: '',
email: '',
}
}
}

99
src/models/task.js Normal file
View File

@ -0,0 +1,99 @@
import AbstractModel from './abstractModel';
import UserModel from './user'
export default class TaskModel extends AbstractModel {
constructor(data) {
super(data)
// Make date objects from timestamps
this.dueDate = this.parseDateIfNessecary(this.dueDate)
this.startDate = this.parseDateIfNessecary(this.startDate)
this.endDate = this.parseDateIfNessecary(this.endDate)
this.reminderDates = this.reminderDates.map(d => {
return this.parseDateIfNessecary(d)
})
this.reminderDates.push(null) // To trigger the datepicker
// Parse the repeat after into something usable
this.parseRepeatAfter()
// Parse the assignees into user models
this.assignees = this.assignees.map(a => {
return new UserModel(a)
})
this.createdBy = new UserModel(this.createdBy)
}
defaults() {
return {
id: 0,
text: '',
description: '',
done: false,
priority: 0,
labels: [],
assignees: [],
dueDate: 0,
startDate: 0,
endDate: 0,
repeatAfter: 0,
reminderDates: [],
subtasks: [],
parentTaskID: 0,
createdBy: UserModel,
created: 0,
updated: 0,
listID: 0, // Meta, only used when creating a new task
sortBy: 'duedate', // Meta, only used when listing all tasks
}
}
/////////////////
// Helper functions
///////////////
/**
* Makes a js date object from a unix timestamp (in seconds).
* @param unixTimestamp
* @returns {*}
*/
parseDateIfNessecary(unixTimestamp) {
let dateobj = new Date(unixTimestamp * 1000)
if (unixTimestamp === 0) {
return null
}
return dateobj
}
/**
* Parses the "repeat after x seconds" from the task into a usable js object inside the task.
* This function should only be called from the constructor.
*/
parseRepeatAfter() {
let repeatAfterHours = (this.repeatAfter / 60) / 60
this.repeatAfter = {type: 'hours', amount: repeatAfterHours}
// if its dividable by 24, its something with days, otherwise hours
if (repeatAfterHours % 24 === 0) {
let repeatAfterDays = repeatAfterHours / 24
if (repeatAfterDays % 7 === 0) {
this.repeatAfter.type = 'weeks'
this.repeatAfter.amount = repeatAfterDays / 7
} else if (repeatAfterDays % 30 === 0) {
this.repeatAfter.type = 'months'
this.repeatAfter.amount = repeatAfterDays / 30
} else if (repeatAfterDays % 365 === 0) {
this.repeatAfter.type = 'years'
this.repeatAfter.amount = repeatAfterDays / 365
} else {
this.repeatAfter.type = 'days'
this.repeatAfter.amount = repeatAfterDays
}
}
}
}

29
src/models/team.js Normal file
View File

@ -0,0 +1,29 @@
import AbstractModel from './abstractModel'
import UserModel from './user'
import TeamMemberModel from './teamMember'
export default class TeamModel extends AbstractModel {
constructor(data) {
super(data)
// Make the members to usermodels
this.members = this.members.map(m => {
return new TeamMemberModel(m)
})
this.createdBy = new UserModel(this.createdBy)
}
defaults() {
return {
id: 0,
name: '',
description: '',
members: [],
right: 0,
createdBy: {},
created: 0,
updated: 0
}
}
}

13
src/models/teamList.js Normal file
View File

@ -0,0 +1,13 @@
import TeamShareBaseModel from './teamShareBase'
import {merge} from "lodash";
export default class TeamListModel extends TeamShareBaseModel {
defaults() {
return merge(
super.defaults(),
{
listID: 0,
}
)
}
}

14
src/models/teamMember.js Normal file
View File

@ -0,0 +1,14 @@
import UserModel from './user'
import {merge} from 'lodash'
export default class TeamMemberModel extends UserModel {
defaults() {
return merge(
super.defaults(),
{
admin: false,
teamID: 0,
}
)
}
}

View File

@ -0,0 +1,13 @@
import TeamShareBaseModel from './teamShareBase'
import {merge} from 'lodash'
export default class TeamNamespaceModel extends TeamShareBaseModel {
defaults() {
return merge(
super.defaults(),
{
namespaceID: 0,
}
)
}
}

View File

@ -0,0 +1,17 @@
import AbstractModel from './abstractModel'
/**
* This class is a base class for common team sharing model.
* It is extended in a way so it can be used for namespaces as well for lists.
*/
export default class TeamShareBaseModel extends AbstractModel {
defaults() {
return {
teamID: 0,
right: 0,
created: 0,
updated: 0
}
}
}

13
src/models/user.js Normal file
View File

@ -0,0 +1,13 @@
import AbstractModel from './abstractModel'
export default class UserModel extends AbstractModel {
defaults() {
return {
id: 0,
email: '',
username: '',
created: 0,
updated: 0
}
}
}

14
src/models/userList.js Normal file
View File

@ -0,0 +1,14 @@
import UserShareBaseModel from './userShareBase'
import {merge} from 'lodash'
// This class extends the user share model with a 'rights' parameter which is used in sharing
export default class UserListModel extends UserShareBaseModel {
defaults() {
return merge(
super.defaults(),
{
listID: 0,
}
)
}
}

View File

@ -0,0 +1,14 @@
import UserShareBaseModel from "./userShareBase";
import {merge} from 'lodash'
// This class extends the user share model with a 'rights' parameter which is used in sharing
export default class UserNamespaceModel extends UserShareBaseModel {
defaults() {
return merge(
super.defaults(),
{
namespaceID: 0,
}
)
}
}

View File

@ -0,0 +1,13 @@
import AbstractModel from './abstractModel'
export default class UserShareBaseModel extends AbstractModel {
defaults() {
return {
userID: 0,
right: 0,
created: 0,
updated: 0,
}
}
}