Grooming, new CLI options.

master
Luka Vandervelden 2019-07-07 12:09:54 +02:00
parent 802812e99f
commit f0295031e9
5 changed files with 226 additions and 186 deletions

13
src/column.cr Normal file
View File

@ -0,0 +1,13 @@
require "uuid"
class Column
JSON.mapping({
id: String,
name: String
})
def initialize(@name)
@id = UUID.random.to_s
end
end

View File

@ -4,186 +4,40 @@ require "file_utils"
require "authd"
class Task
JSON.mapping({
id: String,
author: Int32,
title: String,
description: String,
column: String,
assigned_to: Int32?
})
require "./project.cr"
require "./requests.cr"
def initialize(@title, @author, @description, @column)
@id = UUID.random.to_s
end
end
authd_key = nil : String?
storage_directory = "./projects"
class Column
JSON.mapping({
id: String,
name: String
})
def initialize(@name)
@id = UUID.random.to_s
end
end
class Project
JSON.mapping({
id: String,
name: String,
columns: Array(Column),
tasks: Array(Task),
color: {
type: String,
default: "dark"
}
})
def initialize(@name)
@id = UUID.random.to_s
@columns = [Column.new "To do"]
@tasks = [] of Task
@color = "dark"
write!
end
def write!
Dir.mkdir_p "./projects/#{@id}"
File.write "./projects/#{@id}/project.json.new", to_json
FileUtils.mv "./projects/#{@id}/project.json.new",
"./projects/#{@id}/project.json"
end
# FIXME: Transform that exception somehow.
# FIXME: Update to not read everything.
def self.get_from_id(id)
self.all.find(&.id.==(id)).not_nil!
end
def self.all : Array(Project)
# FIXME: switch to an index file per project in a storage directory.
Dir.children("./projects").compact_map do |filename|
begin
Project.from_json File.read "./projects/#{filename}/project.json"
rescue
end
end
rescue
[] of Project
end
end
class Requests::Login
JSON.mapping({
type: String,
login: String,
password: String
})
end
class Requests::Tasks
JSON.mapping({
type: String,
project: String
})
end
class Requests::NewProject
JSON.mapping({
type: String,
name: String
})
end
class Requests::EditProject
JSON.mapping({
type: String,
project: String,
name: String?,
color: String?
})
end
class Requests::NewColumn
JSON.mapping({
type: String,
project: String,
name: String
})
end
class Requests::NewTask
JSON.mapping({
type: String,
project: String,
column: String,
title: String,
description: String
})
end
class Requests::EditTask
JSON.mapping({
type: String,
project: String,
task: String,
column: String?,
title: String?,
description: String?,
assigned_to: Int32?
})
end
class Requests::DeleteTask
JSON.mapping({
type: String,
project: String,
task: String
})
end
class Requests::EditColumn
JSON.mapping({
type: String,
project: String,
column: String,
name: String?
})
end
class Requests::DeleteColumn
JSON.mapping({
type: String,
project: String,
column: String
})
end
class Requests::GetUser
JSON.mapping({
type: String,
uid: Int32
})
end
authd = AuthD::Client.new
# Itll get replaced later. But FIXME, this is only a temporary workaround.
authd = nil.unsafe_as AuthD::Client
Kemal.config.extra_options do |parser|
parser.on "-k file", "--jwt-key file", "Provides the JWT key for authd." do |file|
authd.key = File.read(file).chomp
authd_key = File.read(file).chomp
end
parser.on "-S dir", "--storage dir", "Provides a directory in which to store kanbands data and projects." do |dir|
storage_directory = dir
end
end
sockets = [] of HTTP::WebSocket
users = {} of HTTP::WebSocket => AuthD::User
get "/" do
File.read "index.html"
end
get "/style.css" do
File.read "style.css"
end
get "/main.js" do
File.read "main.js"
end
ws "/socket" do |socket|
socket.on_close do
users.delete socket
@ -220,7 +74,7 @@ ws "/socket" do |socket|
socket.send({
type: "list-projects",
projects: Project.all
projects: Project.all storage_directory
}.to_json)
when "new-project"
user = users[socket] # FIXME: make it an authentication error
@ -229,6 +83,8 @@ ws "/socket" do |socket|
project = Project.new request.name
project.write! storage_directory
# FIXME: Only notify concerned users.
sockets.each &.send({
type: "project",
@ -239,7 +95,7 @@ ws "/socket" do |socket|
request = Requests::Tasks.from_json message_as_s
project = Project.get_from_id request.project
project = Project.get_from_id request.project, storage_directory
socket.send({
type: "project",
@ -250,7 +106,7 @@ ws "/socket" do |socket|
request = Requests::EditProject.from_json message_as_s
project = Project.get_from_id request.project
project = Project.get_from_id request.project, storage_directory
if name = request.name
project.name = name
@ -260,7 +116,7 @@ ws "/socket" do |socket|
project.color = color
end
project.write!
project.write! storage_directory
# FIXME: Only notify concerned users.
sockets.each &.send({
@ -272,10 +128,10 @@ ws "/socket" do |socket|
request = Requests::NewColumn.from_json message_as_s
project = Project.get_from_id request.project
project = Project.get_from_id request.project, storage_directory
project.columns << Column.new request.name
project.write!
project.write! storage_directory
# FIXME: Only notify concerned users.
sockets.each &.send({
@ -287,12 +143,12 @@ ws "/socket" do |socket|
request = Requests::NewTask.from_json message_as_s
project = Project.get_from_id request.project
project = Project.get_from_id request.project, storage_directory
column = project.columns.find(&.id.==(request.column)).not_nil!
project.tasks << Task.new request.title, user.uid, request.description, column.id
project.write!
project.write! storage_directory
# FIXME: Only notify concerned users.
sockets.each &.send({
@ -304,7 +160,7 @@ ws "/socket" do |socket|
request = Requests::EditTask.from_json message_as_s
project = Project.get_from_id request.project
project = Project.get_from_id request.project, storage_directory
task = project.tasks.find(&.id.==(request.task)).not_nil!
if column = request.column
@ -329,7 +185,7 @@ ws "/socket" do |socket|
task.assigned_to = assigned_to
end
project.write!
project.write! storage_directory
# FIXME: Only notify concerned users.
sockets.each &.send({
@ -341,11 +197,11 @@ ws "/socket" do |socket|
request = Requests::DeleteTask.from_json message_as_s
project = Project.get_from_id request.project
project = Project.get_from_id request.project, storage_directory
project.tasks.select! &.id.!=(request.task)
project.write!
project.write! storage_directory
# FIXME: Only notify concerned users.
sockets.each &.send({
@ -357,7 +213,7 @@ ws "/socket" do |socket|
request = Requests::EditColumn.from_json message_as_s
project = Project.get_from_id request.project
project = Project.get_from_id request.project, storage_directory
column = project.columns.find(&.id.==(request.column)).not_nil!
if name = request.name
@ -366,7 +222,7 @@ ws "/socket" do |socket|
puts project.columns.to_json
project.write!
project.write! storage_directory
# FIXME: Only notify concerned users.
sockets.each &.send({
@ -377,12 +233,12 @@ ws "/socket" do |socket|
user = users[socket]
request = Requests::DeleteColumn.from_json message_as_s
project = Project.get_from_id request.project
project = Project.get_from_id request.project, storage_directory
project.columns.select! &.id.!=(request.column)
project.tasks.select! &.column.!=(request.column)
project.write!
project.write! storage_directory
# FIXME: Only notify concerned users.
sockets.each &.send({
@ -402,5 +258,10 @@ ws "/socket" do |socket|
end
end
Kemal.run
Kemal.run do
authd = AuthD::Client.new
key = authd_key
authd.key = key if key.is_a? String
end

54
src/project.cr Normal file
View File

@ -0,0 +1,54 @@
require "uuid"
require "file_utils"
require "./task.cr"
require "./column.cr"
class Project
JSON.mapping({
id: String,
name: String,
columns: Array(Column),
tasks: Array(Task),
color: {
type: String,
default: "dark"
}
})
def initialize(@name)
@id = UUID.random.to_s
@columns = [Column.new "To do"]
@tasks = [] of Task
@color = "dark"
end
def write!(storage)
Dir.mkdir_p "#{storage}/#{@id}"
File.write "#{storage}/#{@id}/project.json.new", to_json
FileUtils.mv "#{storage}/#{@id}/project.json.new",
"#{storage}/#{@id}/project.json"
end
# FIXME: Transform that exception somehow.
# FIXME: Update to not read everything.
def self.get_from_id(id, storage)
self.all(storage).find(&.id.==(id)).not_nil!
end
def self.all(storage) : Array(Project)
# FIXME: switch to an index file per project in a storage directory.
Dir.children(storage).compact_map do |filename|
begin
Project.from_json File.read "#{storage}/#{filename}/project.json"
rescue
end
end
rescue
[] of Project
end
end

95
src/requests.cr Normal file
View File

@ -0,0 +1,95 @@
require "json"
class Requests::Login
JSON.mapping({
type: String,
login: String,
password: String
})
end
class Requests::Tasks
JSON.mapping({
type: String,
project: String
})
end
class Requests::NewProject
JSON.mapping({
type: String,
name: String
})
end
class Requests::EditProject
JSON.mapping({
type: String,
project: String,
name: String?,
color: String?
})
end
class Requests::NewColumn
JSON.mapping({
type: String,
project: String,
name: String
})
end
class Requests::NewTask
JSON.mapping({
type: String,
project: String,
column: String,
title: String,
description: String
})
end
class Requests::EditTask
JSON.mapping({
type: String,
project: String,
task: String,
column: String?,
title: String?,
description: String?,
assigned_to: Int32?
})
end
class Requests::DeleteTask
JSON.mapping({
type: String,
project: String,
task: String
})
end
class Requests::EditColumn
JSON.mapping({
type: String,
project: String,
column: String,
name: String?
})
end
class Requests::DeleteColumn
JSON.mapping({
type: String,
project: String,
column: String
})
end
class Requests::GetUser
JSON.mapping({
type: String,
uid: Int32
})
end

17
src/task.cr Normal file
View File

@ -0,0 +1,17 @@
require "uuid"
class Task
JSON.mapping({
id: String,
author: Int32,
title: String,
description: String,
column: String,
assigned_to: Int32?
})
def initialize(@title, @author, @description, @column)
@id = UUID.random.to_s
end
end