123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579 |
- #!/usr/bin/ruby
- #
- # This file is part of centurio.work/ing/commands.
- #
- # centurio.work/ing/commands is free software: you can redistribute it and/or
- # modify it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or (at your
- # option) any later version.
- #
- # centurio.work/ing/commands is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- # Public License for more details.
- #
- # You should have received a copy of the GNU General Public License along with
- # centurio.work/ing/commands (file COPYING in the main directory). If not, see
- # <http://www.gnu.org/licenses/>.
- require 'rubygems'
- require 'json'
- require 'xml/smart'
- require 'riddl/server'
- require 'fileutils'
- require 'typhoeus'
- require 'sqlite3'
- class ConfigSites < Riddl::Implementation
- def response
- Riddl::Parameter::Complex.new('ui','text/html',File.open(File.join(__dir__,'template','index.html')))
- end
- end
- class GetAllConfigs < Riddl::Implementation
- def response
- Dir.chdir( __dir__ + '/data')
- databack = JSON::pretty_generate(Dir.glob('*/').sort_by{|x| x.downcase});
- Dir.chdir( __dir__)
- Riddl::Parameter::Complex.new('list','application/json',databack)
- end
- end
- class GetAllVisus < Riddl::Implementation
- def response
-
- Riddl::Parameter::Complex.new('ui','text/html',File.open(File.join(__dir__,'data', @r[-2],'visus.html')))
- end
- end
- class Get < Riddl::Implementation
- def response
- #Riddl::Parameter::Complex.new('ui','text/html',File.open(File.join(__dir__,'template','template.html')))
- Riddl::Parameter::Complex.new('ui','text/html',File.open(File.join(__dir__,'data', @r.last,'index.html')))
- end
- end
- class GetAllData < Riddl::Implementation
- def response
-
- fname = File.join('data',@r[-2],'data.db')
- db = SQLite3::Database.open fname
- if !db.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='Entries';").empty?
-
- #db.execute "CREATE TABLE IF NOT EXISTS Entries(seriennummer TEXT PRIMARY KEY, produktcode TEXT, activity TEXT, cpeeInstance INTEGER)"
- db.results_as_hash = true
- alldata = {};
- alldata["data"] = (db.execute "Select * from Entries ORDER BY __orderID__ ASC")
-
-
- Riddl::Parameter::Complex.new('value','application/json',JSON.dump(alldata))
-
- else
- Riddl::Parameter::Complex.new('value','application/json',JSON.dump({}))
-
- end
-
- end
- end
- class GetNData < Riddl::Implementation
- def response
- fname = File.join('data',@r[-2],'data.db')
- db = SQLite3::Database.open fname
- if !db.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='Entries';").empty?
- db.results_as_hash = true
- alldata = {};
- alldata["data"] = (db.execute "Select * from Entries ORDER BY __orderID__ ASC LIMIT 1 OFFSET " + @r[-1])
- Riddl::Parameter::Complex.new('value','application/json',JSON.dump(alldata))
- else
- Riddl::Parameter::Complex.new('value','application/json',JSON.dump({}))
- end
- end
- end
- class DeleteNData < Riddl::Implementation
- def response
- fname = File.join('data',@r[-2],'data.db')
- db = SQLite3::Database.open fname
- if !db.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='Entries';").empty?
- db.results_as_hash = true
- alldata = {};
- alldata["data"] = (db.execute "Select * from Entries ORDER BY __orderID__ ASC LIMIT 1 OFFSET " + @r[-1])
- if alldata["data"] != []
-
-
- id = alldata["data"][0]["__orderID__"].to_s
- db.execute("DELETE FROM Entries WHERE __orderID__ = '" + id + "'")
- end
- else
- nil
- end
- @a[0].send("reset")
- end
- end
- # used when executed from e.g. website, in such a case no cpee instance is given
- class AddEntry < Riddl::Implementation
- def response
- newEntry = JSON.parse(@p[0].value.read)
-
- fname = File.join('data',@r.last,'data.db')
- db = SQLite3::Database.open fname
-
- # in case primary key is given
- # PRIMARY KEY Momentan noch nicht implementiert
- if newEntry.has_key?("pkvalue")
- db.execute "CREATE TABLE IF NOT EXISTS Entries(__orderID__ INTEGER PRIMARY KEY AUTOINCREMENT, alldata TEXT, pkvalue TEXT, cpeeInstance INTEGER)"
- db.execute("INSERT OR REPLACE INTO Entries (alldata, pkvalue, cpeeInstance) VALUES (?,?,?)",JSON.dump(newEntry["alldata"]), newEntry["pkvalue"], "Direkt")
- hash = {__orderID__: db.execute("select last_insert_rowid()")[0], alldata: JSON.dump(newEntry["alldata"]), pkvalue: newEntry["pkvalue"], cpeeInstance: "Direkt"};
- else
- db.execute "CREATE TABLE IF NOT EXISTS Entries(__orderID__ INTEGER PRIMARY KEY AUTOINCREMENT, alldata TEXT, cpeeInstance INTEGER)"
- db.execute("INSERT OR REPLACE INTO Entries (alldata, cpeeInstance) VALUES (?,?)",JSON.dump(newEntry["alldata"]), "Direkt")
- hash = {__orderID__: db.execute("select last_insert_rowid()")[0], alldata: JSON.dump(newEntry["alldata"]), cpeeInstance: "Direkt"};
- end
-
-
-
- @a[0].send(JSON.dump(hash))
- nil
-
- end
- end
- class Put < Riddl::Implementation
- def self::putentry(r, p, h)
-
- Dir.mkdir(File.join('data',r.last)) rescue nil
- Dir.mkdir(File.join('data',r.last, "js")) rescue nil
- Dir.mkdir(File.join('data',r.last, "visus")) rescue nil
-
-
- #prevent overriding ui and index in case user changed something there
- if !File.file?(File.join('data',r.last,'js/ui.js'))
- File.write(File.join('data',r.last,'js/ui.js'),File.open("defaultContent/js/ui.js").read)
- end
-
- if !File.file?(File.join('data',r.last,'index.html'))
- file = File.open("defaultContent/index.html").read
- newfile = file.gsub("!replaceThisString!", r.last)
- File.write(File.join('data',r.last,'index.html'), newfile)
- end
-
- #prevent overriding visualization
- if !File.file?(File.join('data',r.last,'visus.html'))
- File.write(File.join('data',r.last,'visus.html'),File.open("defaultContent/visus.html").read)
- end
-
-
- fname = File.join('data',r.last,'data.db')
- db = SQLite3::Database.open fname
-
-
- #in case primary key is given
- if p[1] != nil
- keyfunction = ""
- if p[2] != nil
- keyfunction = p[2].value
- end
- db.execute "CREATE TABLE IF NOT EXISTS Entries(__orderID__ INTEGER PRIMARY KEY AUTOINCREMENT, alldata TEXT, pkvalue TEXT " + keyfunction + ", cpeeInstance INTEGER)"
- db.execute("INSERT OR REPLACE INTO Entries (alldata, pkvalue, cpeeInstance) VALUES (?,?,?)",p[0].value, p[1].value, h['CPEE_INSTANCE'])
- hash = {__orderID__: db.execute("select last_insert_rowid()")[0], alldata: p[0].value, pkvalue: p[1].value, cpeeInstance: h['CPEE_INSTANCE']};
- else
- db.execute "CREATE TABLE IF NOT EXISTS Entries(__orderID__ INTEGER PRIMARY KEY AUTOINCREMENT, alldata TEXT, cpeeInstance INTEGER)"
- db.execute("INSERT OR REPLACE INTO Entries (alldata, cpeeInstance) VALUES (?,?)",p[0].value, h['CPEE_INSTANCE'])
- hash = {__orderID__: db.execute("select last_insert_rowid()")[0], alldata: p[0].value, cpeeInstance: h['CPEE_INSTANCE']};
- end
- hash;
- end
-
-
- def response
- hash = Put::putentry(@r, @p, @h)
- @a[0].send(JSON.dump(hash))
- nil
- end
- end
- class PutPrio < Riddl::Implementation
- def response
- hash = Put::putentry(@r, @p, @h) #add entry
- hash = Move::moveentry(hash[:__orderID__][0], 0,@r) #move to front
- @a[0].send("reset")
- nil
- end
- end
- class PutPrioN < Riddl::Implementation
- def response
-
- #move all back
- fname = File.join('data',@r.last,'data.db')
- db = SQLite3::Database.open fname
- #Updating entries directly + X would result in unique constraint failed
- #Therefore updates first to negative values then *-1
- db.execute "UPDATE Entries SET __orderID__= 0 - (__orderID__ + " + @p[1].value + ")"
- db.execute "UPDATE Entries SET __orderID__= __orderID__ *-1"
- #Add entries
- i = 0
- while i < @p[1].value.to_i do
- #db.execute("INSERT OR REPLACE INTO Entries (__orderID__, alldata, cpeeInstance) VALUES (?,?,?)",i, @p[0].value, @h['CPEE_INSTANCE'])
-
- #in case primary key is given
- if @p[2] != nil
- db.execute("INSERT OR REPLACE INTO Entries (__orderID__, alldata, pkvalue, cpeeInstance) VALUES (?,?,?,?)",i, @p[0].value, @p[2].value, @h['CPEE_INSTANCE'])
- else
- db.execute("INSERT OR REPLACE INTO Entries (__orderID__, alldata, cpeeInstance) VALUES (?,?,?)",i, @p[0].value, @h['CPEE_INSTANCE'])
- end
- i +=1
- end
-
- @a[0].send("reset")
- nil
- end
- end
- class Move < Riddl::Implementation
- def self::moveentry(from, to,r)
- fname = File.join('data',r.last,'data.db')
- db = SQLite3::Database.open fname
-
-
- #getMaxID
- result = db.execute "SELECT MAX(__orderID__) FROM Entries"
- if(result[0][0] == nil)
- maxImgId = 0
- else
- maxImgId = result[0][0] +1
- end
-
- i = 0
- if to < from
- while to < from do
-
- #nutze max ID zum tauschen
- db.execute("UPDATE Entries SET __orderID__ = ? WHERE __orderID__ = ?", [maxImgId, from - 1])
- db.execute("UPDATE Entries SET __orderID__ = ? WHERE __orderID__ = ?", [from - 1, from])
- db.execute("UPDATE Entries SET __orderID__ = ? WHERE __orderID__ = ?", [from, maxImgId])
-
- from -=1
- end
- elsif from < to
-
- while from < to do
-
- #nutze max ID zum tauschen
- db.execute("UPDATE Entries SET __orderID__ = ? WHERE __orderID__ = ?", [maxImgId, from + 1])
- db.execute("UPDATE Entries SET __orderID__ = ? WHERE __orderID__ = ?", [from + 1, from])
- db.execute("UPDATE Entries SET __orderID__ = ? WHERE __orderID__ = ?", [from, maxImgId])
-
- from +=1
- end
-
- end
- nil
- end
-
- def response
- movement = JSON.parse(@p[0].value.read)
- from = movement["From"]
- to = movement["To"]
- hash = Move::moveentry(from, to,@r)
- nil
- end
- end
- class Update < Riddl::Implementation
- def response
- fname = File.join('data',@r.last,'data.db')
- db = SQLite3::Database.open fname
-
- updateData = JSON.parse(@p[0].value.read)
-
- orderID = updateData["ID"]
- alldata = JSON.generate(updateData["alldata"])
- db.execute("UPDATE Entries SET alldata = ? WHERE __orderID__ = ?", [alldata, orderID])
- nil
- end
- end
- class Storesortedtable < Riddl::Implementation
- def response
- fname = File.join('data',@r.last,'data.db')
- db = SQLite3::Database.open fname
-
- #invert keys from + to - to prevent duplicate primary keys when reordering
- db.execute("UPDATE Entries SET __orderID__ = __orderID__ *-1 -1")
-
- updateData = JSON.parse(@p[0].value.read)
-
- updateData.each_with_index do |child, idx|
- db.execute("UPDATE Entries SET __orderID__ = ? WHERE __orderID__ = ?", [idx, child.to_i*-1 -1])
- end
-
-
- #security
- #in case there are negative entries remaining add them with positive value to the end
-
- result = db.execute "SELECT MAX(__orderID__) FROM Entries"
- if(result[0][0] == nil)
- maxorderID = 0
- else
- maxorderID = result[0][0] +1
- end
-
- resultpattern = db.execute "SELECT * FROM Entries WHERE __orderID__ < 0"
- resultpattern.each do |row2|
- db.execute("UPDATE Entries SET __orderID__ = ? WHERE __orderID__ = ?", [maxorderID, row2[0]]);
- maxorderID = maxorderID +1;
- end
-
- @a[0].send("reset")
-
- nil
- end
- end
- class Delete < Riddl::Implementation
- def response
- fname = File.join('data',@r.last,'data.db')
- db = SQLite3::Database.open fname
- alldata = @p[0].value.read
- db.execute("DELETE FROM Entries WHERE alldata = '" + alldata + "'")
- nil
- end
- end
- class DeleteID < Riddl::Implementation
- def self::remove(dbfolder, id)
-
- fname = File.join('data',dbfolder,'data.db')
- db = SQLite3::Database.open fname
- db.execute("DELETE FROM Entries WHERE __orderID__ = '" + id.to_s + "'")
-
- end
- def response
- DeleteID::remove(@r.last, @p[0].value.read)
- nil
- end
- end
- class DeleteIDDirect < Riddl::Implementation
- def response
- DeleteID::remove(@r.last, @p[0].value)
- nil
- end
- end
- class DeletePK < Riddl::Implementation
- def response
-
- fname = File.join('data',@r.last,'data.db')
- db = SQLite3::Database.open fname
- pkvalue = @p[0].value
- db.execute("DELETE FROM Entries WHERE pkvalue = '" + pkvalue + "'")
-
- nil
- end
- end
- class SearchPK < Riddl::Implementation
- def response
-
- fname = File.join('data',@r[-4],'data.db')
- db = SQLite3::Database.open fname
- pkvalue = @r.last
- if !db.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='Entries';").empty?
- db.results_as_hash = true
- alldata = {};
- alldata["data"] = (db.execute "Select * from Entries WHERE pkvalue = '" + pkvalue + "'")
- Riddl::Parameter::Complex.new('value','application/json',JSON.dump(alldata))
- else
- Riddl::Parameter::Complex.new('value','application/json',JSON.dump({}))
- end
- end
- end
- class GetNext < Riddl::Implementation
- def response
- fname = File.join('data',@r[-2],'data.db')
- db = SQLite3::Database.open fname
-
- #get value
- db.results_as_hash = true
- alldata = {};
- alldata["data"] = (db.execute "Select * from Entries ORDER BY __orderID__ ASC LIMIT 1")[0]
-
- Riddl::Parameter::Complex.new('value','application/json',JSON.dump(alldata))
- end
- end
- class DeleteNext < Riddl::Implementation
- def response
- fname = File.join('data',@r[-2],'data.db')
- db = SQLite3::Database.open fname
-
- #get value
- db.results_as_hash = true
- alldata = {};
- alldata["data"] = (db.execute "Select * from Entries ORDER BY __orderID__ ASC LIMIT 1")[0]
-
- #remove from DB
- DeleteID::remove(@r[-2], alldata["data"]["__orderID__"])
-
- @a[0].send("reset")
- Riddl::Parameter::Complex.new('value','application/json',JSON.dump(alldata))
- end
- end
- class DeleteAll < Riddl::Implementation
- def response
-
- File.unlink(File.join('data',@r.last,'data.db')) rescue nil
- nil
- end
- end
- class SSE < Riddl::SSEImplementation #{{{
- def onopen
- signals = @a[0]
- signals.add self
- send 'started'
- true
- end
- def onclose
- signals = @a[0]
- signals.remove self
- nil
- end
- end #}}}
- class Signaling # {{{
- def initialize
- @binding = []
- end
- def add(binding)
- @binding << binding
- end
- def remove(binding)
- @binding.delete(binding)
- end
- def length
- @binding.length
- end
- def send(value)
- @binding.each do |b|
- b.send(value)
- end
- end
- end #}}}
- server = Riddl::Server.new(File.join(__dir__,'/dashboard.xml'), :host => 'localhost') do |opts|
- accessible_description true
- cross_site_xhr true
- opts[:signals] = {}
- parallel do
- loop do
- opts[:signals].each do |k,v|
- v.send('keepalive')
- end
- sleep 5
- end
- end
- on resource do
- run ConfigSites if get
-
- on resource 'getconfigs' do
- run GetAllConfigs if get
- end
-
-
-
- on resource do |r|
- idx = r[:r][0]
- opts[:signals][idx] ||= Signaling.new
-
-
- run Get if get
- run Put, opts[:signals][idx] if put 'input'
- run PutPrio, opts[:signals][idx] if put 'inputprio'
- run PutPrioN, opts[:signals][idx] if put 'inputNprio'
- run Move if put 'move'
- run Update if put 'update'
- run Storesortedtable, opts[:signals][idx] if put 'storesortedtable'
- run AddEntry, opts[:signals][idx] if post 'directADD'
- run Delete if delete 'deleteMsg'
- run DeleteID if delete 'deleteByID'
- run DeletePK if delete 'deletePK'
- run DeleteAll if delete 'deleteAll'
- run DeleteIDDirect if delete
-
-
- on resource '\d+' do
- run GetNData, opts if get
- run DeleteNData, opts[:signals][idx] if delete
- end
-
- on resource 'sse' do
- run SSE, opts[:signals][idx] if sse
- end
-
- on resource 'data.db' do
- run GetAllData if get
- end
-
-
- on resource 'search' do
- on resource 'PK' do
- on resource '.*' do
- run SearchPK if get
- end
- end
- end
-
- on resource 'visus' do
- run GetAllVisus if get
- end
-
- on resource 'next' do
- run GetNext, opts[:signals][idx] if get
- run DeleteNext, opts[:signals][idx] if delete
- end
-
- end
- end
- end.loop!
|