From d608f73772a9181911cccbf0e518371a6a257b9d Mon Sep 17 00:00:00 2001
From: alexey
Date: Sat, 22 Feb 2025 23:28:36 +0300
Subject: [PATCH] Receipt create. Part 2
---
app.rb | 122 ++++++++++++++++++++---
classes/db.rb | 66 ++++++++++++-
classes/gitinfo.rb | 4 +-
classes/utilities.rb | 15 +++
db/migrations/202502150000000_create.rb | 2 +-
public/js/jquery.dropdown.min.css | 1 +
public/js/jquery.dropdown.min.js | 1 +
views/header.erb | 5 +
views/rcpcrt.erb | 26 ++++-
views/rcpedit.erb | 125 ++++++++++++++++++++++++
views/receips.erb | 13 ++-
11 files changed, 356 insertions(+), 24 deletions(-)
create mode 100644 classes/utilities.rb
create mode 100755 public/js/jquery.dropdown.min.css
create mode 100755 public/js/jquery.dropdown.min.js
create mode 100644 views/rcpedit.erb
diff --git a/app.rb b/app.rb
index 1e568eb..800a228 100644
--- a/app.rb
+++ b/app.rb
@@ -14,6 +14,7 @@ require_relative "classes/config"
require_relative "classes/gitinfo"
require_relative "classes/db"
require_relative "classes/systeminfo"
+require_relative "classes/utilities"
def print_error_page(error_status, error_meaasge)
@page_name = "Ошибка выполнения"
@@ -22,14 +23,6 @@ def print_error_page(error_status, error_meaasge)
halt erb(:page5xx)
end
-def sanitize_filename(filename)
- filename = filename.strip
- sanitized = filename.gsub(/[^a-zA-Z0-9_]/, "_")
- sanitized.gsub!(/_+/, "_")
- sanitized.gsub!(/^_+|_+$/, "")
- sanitized
-end
-
cfg = IniConfig.new()
db = DBase.new()
@@ -155,11 +148,118 @@ get "/recips" do
erb :receips
end
+get "/recips/:rcp_id" do
+ repo = GitRepo.new(cfg.get_repo, db)
+ if repo.path.nil?
+ print_error_page(503, "Путь к репозиториям не существует")
+ else
+ @repo_data = repo.getrepos
+ @rcp_id = params["rcp_id"]
+ info = db.get_rcp_info_by_id(@rcp_id)
+ @page_name = info[:filepath]
+ @rcp_name = info[:filepath]
+ if session[:rcp_old_description].nil?
+ @old_filepath = info[:filepath]
+ else
+ @old_filepath = session[:rcp_old_filepath]
+ end
+ if session[:rcp_old_description].nil?
+ @old_description = info[:descr]
+ else
+ @old_description = session[:rcp_old_description]
+ end
+ if session[:rcp_old_codedata].nil?
+ @old_codedata = info[:content]
+ else
+ @old_codedata = session[:rcp_old_codedata]
+ end
+ if session[:rcp_old_gitlst].nil?
+ @old_gitlst = info[:repos_list]
+ else
+ @old_gitlst = session[:rcp_old_gitlst]
+ end
+ @error_data = session[:rcpcreate_error]
+ session[:rcpcreate_error] = nil
+ session[:rcp_old_filepath] = nil
+ session[:rcp_old_description] = nil
+ session[:rcp_old_codedata] = nil
+ session[:rcp_old_gitlst] = nil
+ erb :rcpedit
+ end
+end
+
+post "/recips/:rcp_id" do
+ rcp_id = params["rcp_id"]
+ session[:rcp_old_filepath] = params["filepath"]
+ session[:rcp_old_description] = params["description"]
+ session[:rcp_old_codedata] = params["codedata"]
+ session[:rcp_old_gitlst] = params["gitlst"]
+ if params["filepath"].nil? || params["description"].nil? || params["filepath"].strip == "" || params["description"].strip == ""
+ session[:rcpcreate_error] = "Имя рецепта и описание не должны быть пустыми"
+ redirect url("/recips/#{rcp_id}")
+ else
+ @error_data = db.updaterecip(rcp_id, params["filepath"], params["description"], params["codedata"], params["gitlst"])
+ unless @error_data.nil?
+ session[:rcpcreate_error] = @error_data
+ redirect url("/recips/#{rcp_id}")
+ else
+ redirect "/recips"
+ end
+ end
+end
+
+post "/rcpdelete/:rcp_id" do
+ input_name = params["rcpnamedup"]
+ rcp_id = params["rcp_id"]
+ info = db.get_rcp_info_by_id(rcp_id)
+ if info.nil?
+ print_error_page(404, "Рецепта не существует")
+ else
+ if info[:filepath] == input_name
+ db.delete_rcp(rcp_id)
+ end
+ redirect "/recips"
+ end
+end
+
+post "/rcpdelete" do
+ redirect "/recips"
+end
+
get "/rcpcreate" do
@page_name = "Создать новый рецепт"
- @error_data = session[:rcpcreate_error]
- session[:gitcreate_error] = nil
- erb :rcpcrt
+ @old_filepath = session[:rcp_old_filepath]
+ @old_description = session[:rcp_old_description]
+ @old_codedata = session[:rcp_old_codedata]
+ @old_gitlst = session[:rcp_old_gitlst]
+ repo = GitRepo.new(cfg.get_repo, db)
+ if repo.path.nil?
+ print_error_page(503, "Путь к репозиториям не существует")
+ else
+ @repo_data = repo.getrepos
+ @error_data = session[:rcpcreate_error]
+ session[:rcpcreate_error] = nil
+ erb :rcpcrt
+ end
+end
+
+post "/rcpcreate" do
+ session[:rcp_old_filepath] = params["filepath"]
+ session[:rcp_old_description] = params["description"]
+ session[:rcp_old_codedata] = params["codedata"]
+ session[:rcp_old_gitlst] = params["gitlst"]
+ if params["filepath"].nil? || params["description"].nil? || params["filepath"].strip == "" || params["description"].strip == ""
+ session[:rcpcreate_error] = "Имя рецепта и описание не должны быть пустыми"
+ redirect "/rcpcreate"
+ else
+ @error_data = db.createrecip(params["filepath"], params["description"], params["codedata"], params["gitlst"])
+ unless @error_data.nil?
+ session[:rcpcreate_error] = @error_data
+ redirect "/rcpcreate"
+ else
+ redirect "/recips"
+ end
+ end
end
not_found do
diff --git a/classes/db.rb b/classes/db.rb
index c57ac48..77188d9 100644
--- a/classes/db.rb
+++ b/classes/db.rb
@@ -17,8 +17,8 @@ class DBase
def creategit(project_name, description)
@error = nil
- data = Repos.where(reponame: project_name)
- unless data.nil?
+ data = Repos.where(reponame: project_name).first
+ if data.nil?
id = Repos.insert(reponame: project_name, descr: description, public: 1)
@last_id = id
else
@@ -46,4 +46,66 @@ class DBase
Repos.where(id: id).delete
end
end
+
+ def createrecip(filepath, description, codedata, gitlist)
+ error_data = nil
+ filepath_san = sanitize_rcptname(filepath)
+ is_data = Recips.where(filepath: filepath_san).first
+ if codedata.nil? || codedata.strip == ""
+ error_data
+ else
+ if is_data.nil?
+ id = Recips.insert(filepath: filepath_san, descr: description, content: codedata)
+ @last_id = id
+ if !gitlist.nil? && gitlist.length > 0
+ gitlist.each do |item|
+ data = Repos.where(id: item.to_i).first
+ unless data.nil?
+ RepocRecips.insert(repo_id: data[:id], recip_id: id)
+ end
+ end
+ end
+ error_data
+ else
+ "Рецепт с таким именем #{filepath_san} уже существует"
+ end
+ end
+ end
+
+ def updaterecip(id, filepath, description, codedata, gitlist)
+ error_data = nil
+ filepath_san = sanitize_rcptname(filepath)
+ is_data = Recips.where(filepath: filepath_san).first
+ if codedata.nil? || codedata.strip == ""
+ error_data
+ else
+ unless is_data.nil?
+ Recips.where(id: id.to_i).update(filepath: filepath_san, descr: description, content: codedata)
+ RepocRecips.where(recip_id: id.to_i).delete
+ if !gitlist.nil? && gitlist.length > 0
+ gitlist.each do |item|
+ data = Repos.where(id: item.to_i).first
+ unless data.nil?
+ RepocRecips.insert(repo_id: data[:id], recip_id: id)
+ end
+ end
+ end
+ error_data
+ else
+ "Рецепт с таким именем #{filepath_san} не существует"
+ end
+ end
+ end
+
+ def get_rcp_info_by_id(rcpi_id)
+ info = Recips[rcpi_id.to_i]
+ gits = RepocRecips.where(recip_id: info[:id])
+ info[:repos_list] = gits.map { |item| item[:repo_id].to_s }
+ info
+ end
+
+ def delete_rcp(id)
+ RepocRecips.where(recip_id: id.to_i).delete
+ Recips.where(id: id.to_i).delete
+ end
end
diff --git a/classes/gitinfo.rb b/classes/gitinfo.rb
index 91f0f86..0faff98 100644
--- a/classes/gitinfo.rb
+++ b/classes/gitinfo.rb
@@ -67,13 +67,13 @@ class GitRepo
db_info = @db.get_repo_info_by_name(repo_name)
unless db_info.nil?
db_info = db_info.first
- repos_data << { :reponame => db_info.reponame, :descr => db_info.descr, :public => db_info.public }
+ repos_data << { :reponame => db_info.reponame, :descr => db_info.descr, :public => db_info.public, :id => db_info.id }
else
result = create_git_db_only(repo_name)
if result.nil?
db_info = @db.get_repo_info_by_name(repo_name)
db_info = db_info.first
- repos_data << { :reponame => db_info.reponame, :descr => db_info.descr, :public => db_info.public }
+ repos_data << { :reponame => db_info.reponame, :descr => db_info.descr, :public => db_info.public, :id => db_info.id }
end
end
end
diff --git a/classes/utilities.rb b/classes/utilities.rb
new file mode 100644
index 0000000..ca4b704
--- /dev/null
+++ b/classes/utilities.rb
@@ -0,0 +1,15 @@
+def sanitize_filename(filename)
+ filename = filename.strip
+ sanitized = filename.gsub(/[^a-zA-Z0-9_]/, "_")
+ sanitized.gsub!(/_+/, "_")
+ sanitized.gsub!(/^_+|_+$/, "")
+ sanitized
+end
+
+def sanitize_rcptname(filename)
+ filename = filename.strip
+ sanitized = filename.gsub(/[^a-zA-Z0-9_\.]/, "_")
+ sanitized.gsub!(/_+/, "_")
+ sanitized.gsub!(/^_+|_+$/, "")
+ sanitized
+end
diff --git a/db/migrations/202502150000000_create.rb b/db/migrations/202502150000000_create.rb
index 1be9a62..dce80c3 100644
--- a/db/migrations/202502150000000_create.rb
+++ b/db/migrations/202502150000000_create.rb
@@ -27,7 +27,7 @@ Sequel.migration do
primary_key :id
String :content, text: true
String :filepath, text: true
- String :desct, text: true
+ String :descr, text: true
Datetime :create_at, default: Sequel.lit("CURRENT_TIMESTAMP")
end
diff --git a/public/js/jquery.dropdown.min.css b/public/js/jquery.dropdown.min.css
new file mode 100755
index 0000000..b3e2cfe
--- /dev/null
+++ b/public/js/jquery.dropdown.min.css
@@ -0,0 +1 @@
+@-webkit-keyframes iui-fadeIn{0%{opacity:0}100%{opacity:1}}@-moz-keyframes iui-fadeIn{0%{opacity:0}100%{opacity:1}}@-ms-keyframes iui-fadeIn{0%{opacity:0}100%{opacity:1}}@-o-keyframes iui-fadeIn{0%{opacity:0}100%{opacity:1}}@keyframes iui-fadeIn{0%{opacity:0}100%{opacity:1}}@-webkit-keyframes iui-fadeOut{0%{opacity:1}100%{opacity:0}}@-moz-keyframes iui-fadeOut{0%{opacity:1}100%{opacity:0}}@-ms-keyframes iui-fadeOut{0%{opacity:1}100%{opacity:0}}@-o-keyframes iui-fadeOut{0%{opacity:1}100%{opacity:0}}@keyframes iui-fadeOut{0%{opacity:1}100%{opacity:0}}.dropdown-multiple,.dropdown-multiple-label,.dropdown-single{position:relative}.dropdown-multiple-label.active .dropdown-main,.dropdown-multiple.active .dropdown-main,.dropdown-single.active .dropdown-main{display:block;-webkit-animation:iui-fadeIn .2s ease-in forwards;-moz-animation:iui-fadeIn .2s ease-in forwards;-ms-animation:iui-fadeIn .2s ease-in forwards;-o-animation:iui-fadeIn .2s ease-in forwards;animation:iui-fadeIn .2s ease-in forwards}.dropdown-multiple-label.active .dropdown-display-label:after,.dropdown-multiple-label.active .dropdown-display:after,.dropdown-multiple.active .dropdown-display-label:after,.dropdown-multiple.active .dropdown-display:after,.dropdown-single.active .dropdown-display-label:after,.dropdown-single.active .dropdown-display:after{border-top:none;border-bottom:10px solid #999;border-left:5px solid transparent;border-right:5px solid transparent}.dropdown-multiple-label.active .dropdown-display,.dropdown-multiple-label.active .dropdown-display-label,.dropdown-multiple.active .dropdown-display,.dropdown-multiple.active .dropdown-display-label,.dropdown-single.active .dropdown-display,.dropdown-single.active .dropdown-display-label{border-bottom-left-radius:0;border-bottom-right-radius:0}.dropdown-display,.dropdown-display-label{position:relative;display:block;margin-bottom:0;font-size:14px;line-height:1.42857143;vertical-align:middle;touch-action:manipulation;cursor:pointer;user-select:none;background-image:none;border:1px solid #ccc;border-radius:4px;color:#333;background-color:#fff}.dropdown-display-label:after,.dropdown-display:after{content:'';position:absolute;border-top:10px solid #999;border-left:5px solid transparent;border-right:5px solid transparent;top:12px;right:8px}.dropdown-clear-all{background-color:#fff;border:none;font-size:22px;z-index:999;color:#999;position:absolute;right:2px;top:2px;display:none;width:25px;height:30px;text-align:center;line-height:30px}.dropdown-clear-all:focus{outline:0}.dropdown-clear-all:hover{color:#ccc;text-decoration:none}.dropdown-display{white-space:nowrap;padding:6px 20px 6px 12px}.dropdown-multiple:hover .dropdown-clear-all,.dropdown-single:hover .dropdown-clear-all{display:block}.dropdown-display .dropdown-chose-list{display:inline-block;vertical-align:middle;width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dropdown-display .dropdown-chose-list span:before{content:','}.dropdown-display .dropdown-chose-list span:first-child:before{content:''}.dropdown-display .placeholder{display:none}.dropdown-display .placeholder:first-child{position:absolute;height:100%;width:100%;top:0;left:0;color:#999;display:block;text-indent:10px;font-size:13px;line-height:32px}.dropdown-display input{border:0;outline:0}.dropdown-display-label{cursor:text;padding:6px 25px 5px 0}.dropdown-display-label .dropdown-search{display:inline-block}.dropdown-display-label input,.dropdown-display-label input:focus{border:none;outline:0}.dropdown-display-label .dropdown-chose-list{display:inline-block;padding:0 5px}.dropdown-display-label .dropdown-chose-list .placeholder{display:none}.dropdown-display-label .dropdown-selected{position:relative;margin:0 5px 5px 0;padding:0 20px 0 5px;border:1px solid #aaa;max-width:100%;border-radius:3px;background-repeat:repeat-x;color:#333;cursor:default;display:inline-block}.dropdown-display-label .dropdown-selected .del{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0;float:right;line-height:1;color:#999;position:absolute;right:3px;top:0}.dropdown-display-label .dropdown-selected .del:after{content:'\D7';font-size:16px}.dropdown-main{position:absolute;top:100%;left:0;z-index:1010;width:100%;color:#444;box-sizing:border-box;background-color:#fff;border:1px solid #ccc;border-radius:0 0 4px 4px;box-shadow:0 6px 12px rgba(0,0,0,.175);margin-top:-1px;border-top:0;padding:4px 7px;display:none}.dropdown-main ul{overflow-x:hidden;overflow-y:auto;max-height:240px;margin:0;padding:0}.dropdown-main input{margin-top:0;display:block;box-sizing:border-box;height:30px;border:1px solid #ccc;width:100%;text-indent:5px;border-radius:3px}.dropdown-main .dropdown-search{display:block;padding:5px 0}.dropdown-group{font-weight:700}.dropdown-group,.dropdown-option{margin:0;padding-left:12px;list-style:none;line-height:26px;word-wrap:break-word}.dropdown-option{cursor:pointer}.dropdown-option:focus,.dropdown-option:hover{background-color:#efefef;outline:0}.dropdown-option[disabled]{color:#ddd;background-color:#fff;cursor:not-allowed;text-decoration:line-through}.dropdown-option.dropdown-chose:after{content:'';float:right;width:10px;height:10px;background:#4AB1E9;border-radius:100%;margin:8px 5px 0 0}.dropdown-maxItem-alert,.dropdown-minItem-alert{position:absolute;top:0;left:0;background-color:#e4e3e2;width:100%;height:39px;line-height:39px;padding:0 5px;border-radius:5px;color:#999;-webkit-animation:iui-fadeIn .2s ease-in forwards;-moz-animation:iui-fadeIn .2s ease-in forwards;-ms-animation:iui-fadeIn .2s ease-in forwards;-o-animation:iui-fadeIn .2s ease-in forwards;animation:iui-fadeIn .2s ease-in forwards}
diff --git a/public/js/jquery.dropdown.min.js b/public/js/jquery.dropdown.min.js
new file mode 100755
index 0000000..81b256c
--- /dev/null
+++ b/public/js/jquery.dropdown.min.js
@@ -0,0 +1 @@
+(function (e) { "use strict"; function o() { } function n(e, o, n) { var t, i, l, a = null, d = 0; n || (n = {}); var s = function () { d = n.leading === !1 ? 0 : (new Date).getTime(), a = null, l = e.apply(t, i), a || (t = i = null) }; return function () { var r = (new Date).getTime(); d || n.leading !== !1 || (d = r); var c = o - (r - d); return t = this, i = arguments, c <= 0 || c > o ? (clearTimeout(a), a = null, d = r, l = e.apply(t, i), a || (t = i = null)) : a || n.trailing === !1 || (a = setTimeout(s, c)), l } } function t() { var e = this.isLabelMode, o = this.config.searchable, n = o ? '' + this.config.input + "" : ""; return e ? '