diff options
author | Sebastian Reichel <sre@ring0.de> | 2013-03-26 15:52:57 +0100 |
---|---|---|
committer | Sebastian Reichel <sre@ring0.de> | 2013-03-26 15:52:57 +0100 |
commit | 7bfb48ef84384ff0460f273ea5841fba628d2a46 (patch) | |
tree | 898d019f33a554f03cac91495adcb7165344382e /src | |
parent | 03a4e9f901cd36792de2172b4ebb8f6e852fe1cd (diff) | |
download | serial-barcode-scanner-7bfb48ef84384ff0460f273ea5841fba628d2a46.tar.bz2 |
code restructure
Diffstat (limited to 'src')
48 files changed, 1372 insertions, 610 deletions
diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..da0bf41 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,9 @@ +DAEMONS=audio config curses-ui database pdf-invoice pgp scanner-session serial-device web + +all: + @$(foreach dir,$(DAEMONS),cd $(dir) && make all && cd ..;) + +clean: + @$(foreach dir,$(DAEMONS),cd $(dir) && make clean && cd ..;) + +.PHONY: all clean diff --git a/src/audio/Makefile b/src/audio/Makefile new file mode 100644 index 0000000..a6fd629 --- /dev/null +++ b/src/audio/Makefile @@ -0,0 +1,9 @@ +all: audio + +audio: main.vala audio.vala audio-interface.vala + valac -o $@ --pkg gstreamer-0.10 --pkg gio-2.0 $^ + +clean: + rm -rf audio + +.PHONY: all clean diff --git a/src/audio/audio-interface.vala b/src/audio/audio-interface.vala new file mode 100644 index 0000000..89d4a6f --- /dev/null +++ b/src/audio/audio-interface.vala @@ -0,0 +1,23 @@ +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +[DBus (name = "io.mainframe.shopsystem.AudioPlayer")] +public interface AudioPlayer : Object { + public abstract signal void end_of_stream(); + + public abstract void play_system(string file) throws IOError; + public abstract string get_random_user_theme() throws IOError; + public abstract void play_user(string theme, string type) throws IOError; +} diff --git a/src/audio.vala b/src/audio/audio.vala index 3f22e6d..0225c01 100644 --- a/src/audio.vala +++ b/src/audio/audio.vala @@ -1,4 +1,4 @@ -/* Copyright 2012, Sebastian Reichel <sre@ring0.de> +/* Copyright 2012-2013, Sebastian Reichel <sre@ring0.de> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -13,14 +13,15 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -public class AudioPlayer { +[DBus (name = "io.mainframe.shopsystem.AudioPlayer")] +public class AudioPlayerImplementation { private dynamic Gst.Element p; string path; public signal void end_of_stream(); private bool bus_callback(Gst.Bus bus, Gst.Message message) { - switch (message.type) { + switch(message.type) { case Gst.MessageType.EOS: end_of_stream(); break; @@ -29,7 +30,7 @@ public class AudioPlayer { return true; } - public AudioPlayer() { + public AudioPlayerImplementation() { path = Environment.get_current_dir()+"/sounds/"; var alsa = Gst.ElementFactory.make("alsasink", "alsa"); @@ -57,7 +58,8 @@ public class AudioPlayer { return result; } catch (Error e) { - write_to_log("Error: %s\n", e.message); + // TODO + //write_to_log("Error: %s\n", e.message); return {}; } } diff --git a/src/audio/main.vala b/src/audio/main.vala new file mode 100644 index 0000000..f3f64f4 --- /dev/null +++ b/src/audio/main.vala @@ -0,0 +1,38 @@ +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +AudioPlayerImplementation player; + +public static int main(string[] args) { + Bus.own_name( + BusType.SESSION, + "io.mainframe.shopsystem.AudioPlayer", + BusNameOwnerFlags.NONE, + on_bus_aquired, + () => {}, + () => stderr.printf("Could not aquire name\n")); + + new MainLoop().run(); + + return 0; +} + +void on_bus_aquired(DBusConnection con) { + try { + con.register_object("/io/mainframe/shopsystem/audio", player); + } catch(IOError e) { + stderr.printf("Could not register service\n"); + } +} diff --git a/src/config/Makefile b/src/config/Makefile new file mode 100644 index 0000000..0e81ee9 --- /dev/null +++ b/src/config/Makefile @@ -0,0 +1,9 @@ +all: config + +config: main.vala config.vala config-interface.vala + valac -o $@ --pkg gio-2.0 $^ + +clean: + rm -rf config + +.PHONY: all clean diff --git a/src/config/config-interface.vala b/src/config/config-interface.vala new file mode 100644 index 0000000..c34e3a7 --- /dev/null +++ b/src/config/config-interface.vala @@ -0,0 +1,26 @@ +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +[DBus (name = "io.mainframe.shopsystem.Config")] +public interface Config : Object { + public abstract bool has_group(string group_name) throws IOError, KeyFileError; + public abstract bool has_key(string group_name, string key) throws IOError, KeyFileError; + public abstract string get_string(string group_name, string key) throws IOError, KeyFileError; + public abstract bool get_boolean(string group_name, string key) throws IOError, KeyFileError; + public abstract int get_integer(string group_name, string key) throws IOError, KeyFileError; + public abstract int64 get_int64(string group_name, string key) throws IOError, KeyFileError; + public abstract uint64 get_uint64(string group_name, string key) throws IOError, KeyFileError; + public abstract double get_double(string group_name, string key) throws IOError, KeyFileError; +} diff --git a/src/config/config.vala b/src/config/config.vala new file mode 100644 index 0000000..60fd835 --- /dev/null +++ b/src/config/config.vala @@ -0,0 +1,62 @@ +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +[DBus (name = "io.mainframe.shopsystem.Config")] +public class Cfg { + + private KeyFile file; + + public Cfg(string file) { + try { + this.file = new KeyFile(); + this.file.load_from_file(file, KeyFileFlags.NONE); + } catch(Error e) { + error("Could not load configuration file: %s", e.message); + } + } + + public bool has_group(string group_name) throws KeyFileError { + return file.has_group(group_name); + } + + public bool has_key(string group_name, string key) throws KeyFileError { + return file.has_key(group_name, key); + } + + public string get_string(string group_name, string key) throws KeyFileError { + return file.get_string(group_name, key); + } + + public bool get_boolean(string group_name, string key) throws KeyFileError { + return file.get_boolean(group_name, key); + } + + public int get_integer(string group_name, string key) throws KeyFileError { + return file.get_integer(group_name, key); + } + + public int64 get_int64(string group_name, string key) throws KeyFileError { + return file.get_int64(group_name, key); + } + + public uint64 get_uint64(string group_name, string key) throws KeyFileError { + return file.get_uint64(group_name, key); + } + + public double get_double(string group_name, string key) throws KeyFileError { + return file.get_double(group_name, key); + } + +} diff --git a/src/config/main.vala b/src/config/main.vala new file mode 100644 index 0000000..aa971d6 --- /dev/null +++ b/src/config/main.vala @@ -0,0 +1,40 @@ +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +Cfg cfg; + +public static int main(string[] args) { + cfg = new Cfg("../../ktt-shopsystem.cfg"); + + Bus.own_name( + BusType.SESSION, + "io.mainframe.shopsystem.Config", + BusNameOwnerFlags.NONE, + on_bus_aquired, + () => {}, + () => stderr.printf("Could not aquire name\n")); + + new MainLoop().run(); + + return 0; +} + +void on_bus_aquired(DBusConnection con) { + try { + con.register_object("/io/mainframe/shopsystem/config", cfg); + } catch(IOError e) { + stderr.printf("Could not register service\n"); + } +} diff --git a/src/curses-ui/Makefile b/src/curses-ui/Makefile new file mode 100644 index 0000000..5d168ba --- /dev/null +++ b/src/curses-ui/Makefile @@ -0,0 +1,9 @@ +all: curses-ui + +curses-ui: clock.vala curses-ui.vala dialog.vala logo.vala main.vala message_box.vala numbers.vala status.vala ../audio/audio-interface.vala + valac -o $@ --pkg curses -X -lncursesw --pkg posix --pkg gio-2.0 $^ + +clean: + rm -rf curses-ui + +.PHONY: all clean diff --git a/src/ui/clock.vala b/src/curses-ui/clock.vala index e38ad9c..dd3ddcd 100644 --- a/src/ui/clock.vala +++ b/src/curses-ui/clock.vala @@ -1,3 +1,18 @@ +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + using Curses; public class ClockWindow { diff --git a/src/ui/curses-ui.vala b/src/curses-ui/curses-ui.vala index 6676eea..ec007f2 100644 --- a/src/ui/curses-ui.vala +++ b/src/curses-ui/curses-ui.vala @@ -1,3 +1,18 @@ +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + public class CursesUI { MessageBox messages; Dialog dialog; diff --git a/src/ui/dialog.vala b/src/curses-ui/dialog.vala index 29782e5..a8585d4 100644 --- a/src/ui/dialog.vala +++ b/src/curses-ui/dialog.vala @@ -1,3 +1,18 @@ +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + using Curses; public class Dialog { diff --git a/src/curses-ui/logo.vala b/src/curses-ui/logo.vala new file mode 100644 index 0000000..dbc716d --- /dev/null +++ b/src/curses-ui/logo.vala @@ -0,0 +1,45 @@ +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +using Curses; + +public class Logo { + Window win; + + public Logo() { + win = new Window(8, COLS - 2, 0, 1); + win.bkgdset(COLOR_PAIR(1) | Attribute.BOLD); + + win.addstr("\n"); + win.addstr(" _ ___ _____ ____ _ \n"); + win.addstr(" | |/ / ||_ _| / ___|| |__ ___ _ __ \n"); + win.addstr(" | ' /| __|| | \\___ \\| '_ \\ / _ \\| '_ \\ \n"); + win.addstr(" | . \\| |_ | | ___) | | | | (_) | |_) )\n"); + win.addstr(" |_|\\_\\\\__||_| |____/|_| |_|\\___/| .__/ \n"); + win.addstr(" |_| \n"); + + win.clrtobot(); + + win.box(0, 0); + + win.refresh(); + } + + public void redraw() { + win.touchwin(); + win.refresh(); + } + +} diff --git a/src/curses-ui/main.vala b/src/curses-ui/main.vala new file mode 100644 index 0000000..1d79c43 --- /dev/null +++ b/src/curses-ui/main.vala @@ -0,0 +1,49 @@ +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +public MainLoop loop; + +public static int main(string[] args) { + /* handle unix signals */ + Unix.signal_add(Posix.SIGTERM, handle_signals); + Unix.signal_add(Posix.SIGINT, handle_signals); + + AudioPlayer audio = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.AudioPlayer", "/io/mainframe/shopsystem/audio"); + + var ui = new CursesUI(); + + ui.log("KtT Shop System has been started"); + audio.play_system("startup.ogg"); + + /* run mainloop */ + loop.run(); + + ui.log("Stopping Shop System"); + audio.play_system("shutdown.ogg"); + + /* we need to run the mainloop to play audio */ + audio.end_of_stream.connect(() => { loop.quit(); }); + loop.run(); + + /* leave curses mode */ + ui.exit(); + + return 0; +} + +bool handle_signals() { + loop.quit(); + return false; +} diff --git a/src/ui/message_box.vala b/src/curses-ui/message_box.vala index 4f9c3f6..cc258b4 100644 --- a/src/ui/message_box.vala +++ b/src/curses-ui/message_box.vala @@ -1,3 +1,18 @@ +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + using Curses; public class MessageBox { diff --git a/src/ui/numbers.vala b/src/curses-ui/numbers.vala index 8ee00d5..200cf63 100644 --- a/src/ui/numbers.vala +++ b/src/curses-ui/numbers.vala @@ -1,3 +1,18 @@ +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + public class AsciiNumbers { public string[] zero = { diff --git a/src/curses-ui/status.vala b/src/curses-ui/status.vala new file mode 100644 index 0000000..5be6a00 --- /dev/null +++ b/src/curses-ui/status.vala @@ -0,0 +1,39 @@ +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +using Curses; + +public class StatusPanel { + Window win; + + public StatusPanel() { + win = new Window(1, COLS - 2, LINES-1, 1); + win.bkgdset(COLOR_PAIR(2) | Attribute.BOLD); + + win.clrtobot(); + win.refresh(); + } + + public void set(string msg) { + win.mvaddstr(0,1, msg); + win.clrtobot(); + win.refresh(); + } + + public void redraw() { + win.touchwin(); + win.refresh(); + } +} diff --git a/src/database/Makefile b/src/database/Makefile new file mode 100644 index 0000000..70253d2 --- /dev/null +++ b/src/database/Makefile @@ -0,0 +1,9 @@ +all: db + +db: main.vala database.vala db-interface.vala ../price.vapi + valac -o $@ --pkg sqlite3 --pkg gee-1.0 --pkg gio-2.0 $^ + +clean: + rm -rf db + +.PHONY: all clean diff --git a/src/db.vala b/src/database/database.vala index dc1c834..640e175 100644 --- a/src/db.vala +++ b/src/database/database.vala @@ -1,4 +1,4 @@ -/* Copyright 2012, Sebastian Reichel <sre@ring0.de> +/* Copyright 2012-2013, Sebastian Reichel <sre@ring0.de> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -15,109 +15,8 @@ public const int day_in_seconds = 24*60*60; -public struct StockEntry { - public string id; - public string name; - public int amount; - public string memberprice; - public string guestprice; -} - -public struct PriceEntry { - public int64 valid_from; - public Price memberprice; - public Price guestprice; -} - -public struct RestockEntry { - public int64 timestamp; - public int amount; - public string price; - public int supplier; - public int64 best_before_date; -} - -public struct Supplier { - public int64 id; - public string name; - public string postal_code; - public string city; - public string street; - public string phone; - public string website; -} - -public struct UserInfo { - public int id; - public string firstname; - public string lastname; - public string email; - public string gender; - public string street; - public int postcode; - public string city; - public string pgp; - - public bool equals(UserInfo x) { - if(id != x.id) return false; - if(firstname != x.firstname) return false; - if(lastname != x.lastname) return false; - if(email != x.email) return false; - if(gender != x.gender) return false; - if(street != x.street) return false; - if(postcode != x.postcode) return false; - if(city != x.city) return false; - if(pgp != x.pgp) return false; - - return true; - } - - public bool exists_in_db() { - if(id in db.get_member_ids()) - return true; - else - return false; - } - - public bool equals_db() { - return this.equals(db.get_user_info(id)); - } -} - -public struct UserAuth { - public int id; - public bool disabled; - public bool superuser; -} - -public struct Product { - public uint64 ean; - public string name; -} - -public struct InvoiceEntry { - public int64 timestamp; - Product product; - Price price; -} - -public struct StatsInfo { - public int count_articles; - public int count_users; - public Price stock_value; - public Price sales_total; - public Price profit_total; - public Price sales_today; - public Price profit_today; - public Price sales_this_month; - public Price profit_this_month; - public Price sales_per_day; - public Price profit_per_day; - public Price sales_per_month; - public Price profit_per_month; -} - -public class Database { +[DBus (name = "io.mainframe.shopsystem.Database")] +public class DataBase : Object { private class Statement { private Sqlite.Statement stmt; @@ -158,7 +57,8 @@ public class Database { } public string column_text(int index) { - return stmt.column_text(index); + var result = stmt.column_text(index); + return (result != null) ? result : ""; } public int64 column_int64(int index) { @@ -169,8 +69,10 @@ public class Database { private Sqlite.Database db; private static Gee.HashMap<string,string> queries = new Gee.HashMap<string,string>(); private static Gee.HashMap<string,Statement> statements = new Gee.HashMap<string,Statement>(); + //private static HashTable<string,string> queries = new HashTable<string,string>(null, null); + //private static HashTable<string,Statement> statements = new HashTable<string,Statement>(null, null); - public Database(string file) { + public DataBase(string file) { int rc; rc = Sqlite.Database.open(file, out db); @@ -224,10 +126,15 @@ public class Database { foreach(var entry in queries.entries) { statements[entry.key] = new Statement(db, entry.value); } +#if 0 + foreach(var key in queries.get_keys()) { + statements[key] = new Statement(db, queries[key]); + } +#endif } - public Gee.HashMap<string,string> get_products() { - var result = new Gee.HashMap<string,string>(null, null); + public GLib.HashTable<string,string> get_products() { + var result = new GLib.HashTable<string,string>(null, null); statements["products"].reset(); while(statements["products"].step() == Sqlite.ROW) @@ -236,6 +143,7 @@ public class Database { return result; } +#if 0 public stock get_stats_stock() { var result = new stock(); var now = time_t(); @@ -265,7 +173,9 @@ public class Database { return result; } +#endif +#if 0 public profit_per_product get_stats_profit_per_products() { var result = new profit_per_product(); @@ -281,7 +191,9 @@ public class Database { return result; } +#endif +#if 0 public profit_per_weekday get_stats_profit_per_weekday() { var result = new profit_per_weekday(); @@ -313,7 +225,9 @@ public class Database { return result; } +#endif +#if 0 public profit_per_day get_stats_profit_per_day() { var result = new profit_per_day(); var to = time_t(); @@ -340,11 +254,12 @@ public class Database { return result; } +#endif - public Gee.List<StockEntry?> get_stock() { - var result = new Gee.ArrayList<StockEntry?>(); - statements["stock_status"].reset(); + public StockEntry[] get_stock() { + StockEntry[] result = {}; + statements["stock_status"].reset(); while(statements["stock_status"].step() == Sqlite.ROW) { StockEntry entry = { statements["stock_status"].column_text(0), @@ -360,17 +275,17 @@ public class Database { entry.memberprice = @"$mprice"; entry.guestprice = @"$gprice"; - result.add(entry); + result += entry; } return result; } - public Gee.List<PriceEntry?> get_prices(uint64 product) { - var result = new Gee.ArrayList<PriceEntry?>(); + public PriceEntry[] get_prices(uint64 product) { + PriceEntry[] result = {}; + statements["prices"].reset(); statements["prices"].bind_text(1, "%llu".printf(product)); - while(statements["prices"].step() == Sqlite.ROW) { PriceEntry entry = { statements["prices"].column_int64(0), @@ -378,17 +293,17 @@ public class Database { statements["prices"].column_int(2) }; - result.add(entry); + result += entry; } return result; } - public Gee.List<RestockEntry?> get_restocks(uint64 product) { - var result = new Gee.ArrayList<RestockEntry?>(); + public RestockEntry[] get_restocks(uint64 product) { + RestockEntry[] result = {}; + statements["restocks"].reset(); statements["restocks"].bind_text(1, "%llu".printf(product)); - while(statements["restocks"].step() == Sqlite.ROW) { RestockEntry entry = { statements["restocks"].column_int64(0), @@ -400,13 +315,13 @@ public class Database { entry.supplier = statements["restocks"].column_int(3); entry.best_before_date = statements["restocks"].column_int64(4); - result.add(entry); + result += entry; } return result; } - public bool buy(int32 user, uint64 article) { + public bool buy(int32 user, uint64 article) throws DatabaseError { int rc = 0; int64 timestamp = (new DateTime.now_utc()).to_unix(); @@ -417,12 +332,12 @@ public class Database { rc = statements["purchase"].step(); if(rc != Sqlite.DONE) - error("[internal error: %d]".printf(rc)); + throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc); return true; } - public string get_product_name(uint64 article) { + public string get_product_name(uint64 article) throws DatabaseError { statements["product_name"].reset(); statements["product_name"].bind_text(1, "%llu".printf(article)); @@ -432,13 +347,13 @@ public class Database { case Sqlite.ROW: return statements["product_name"].column_text(0); case Sqlite.DONE: - return "unbekanntes Produkt: %llu".printf(article); + throw new DatabaseError.PRODUCT_NOT_FOUND("unknown product: %llu", article); default: - return "[internal error: %d]".printf(rc); + throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc); } } - public int get_product_amount(uint64 article) { + public int get_product_amount(uint64 article) throws DatabaseError { statements["product_amount"].reset(); statements["product_amount"].bind_text(1, "%llu".printf(article)); @@ -448,15 +363,13 @@ public class Database { case Sqlite.ROW: return statements["product_amount"].column_int(0); case Sqlite.DONE: - warning("unbekanntes Produkt: %llu".printf(article)); - return -1; + throw new DatabaseError.PRODUCT_NOT_FOUND("unknown product: %llu", article); default: - warning("[internal error: %d]".printf(rc)); - return -1; + throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc); } } - public Price get_product_price(int user, uint64 article) { + public Price get_product_price(int user, uint64 article) throws DatabaseError { int64 timestamp = (new DateTime.now_utc()).to_unix(); bool member = user != 0; @@ -473,15 +386,13 @@ public class Database { else return statements["price"].column_int(1); case Sqlite.DONE: - write_to_log("unbekanntes Produkt: %llu\n", article); - return 0; + throw new DatabaseError.PRODUCT_NOT_FOUND("unknown product: %llu", article); default: - write_to_log("[internal error: %d]\n", rc); - return 0; + throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc); } } - public bool undo(int32 user) { + public bool undo(int32 user) throws DatabaseError { uint64 pid = 0; int rc = 0; @@ -496,10 +407,9 @@ public class Database { write_to_log("Remove purchase of %s", pname); break; case Sqlite.DONE: - write_to_log("Error: undo not possible without purchases"); - return false; + throw new DatabaseError.PRODUCT_NOT_FOUND("undo not possible without purchases"); default: - error("[internal error: %d]".printf(rc)); + throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc); } statements["undo"].reset(); @@ -507,42 +417,37 @@ public class Database { rc = statements["undo"].step(); if(rc != Sqlite.DONE) - error("[internal error: %d]".printf(rc)); + throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc); return true; } - public bool restock(int user, uint64 product, uint amount, uint price, int supplier, int64 best_before_date) { - if(user > 0) { - int rc = 0; - int64 timestamp = (new DateTime.now_utc()).to_unix(); - - statements["stock"].reset(); - statements["stock"].bind_int(1, user); - statements["stock"].bind_text(2, @"$product"); - statements["stock"].bind_text(3, @"$amount"); - statements["stock"].bind_text(4, @"$price"); - statements["stock"].bind_int64(5, timestamp); - if(supplier > 0) - statements["stock"].bind_int(6, supplier); - else - statements["stock"].bind_null(6); - if(best_before_date > 0) - statements["stock"].bind_int64(7, best_before_date); - else - statements["stock"].bind_null(7); - - rc = statements["stock"].step(); - if(rc != Sqlite.DONE) - error("[internal error: %d]".printf(rc)); + public void restock(int user, uint64 product, uint amount, uint price, int supplier, int64 best_before_date) throws DatabaseError { + int rc = 0; + int64 timestamp = (new DateTime.now_utc()).to_unix(); - return true; - } + statements["stock"].reset(); + statements["stock"].bind_int(1, user); + statements["stock"].bind_text(2, @"$product"); + statements["stock"].bind_text(3, @"$amount"); + statements["stock"].bind_text(4, @"$price"); + statements["stock"].bind_int64(5, timestamp); + if(supplier > 0) + statements["stock"].bind_int(6, supplier); + else + statements["stock"].bind_null(6); + if(best_before_date > 0) + statements["stock"].bind_int64(7, best_before_date); + else + statements["stock"].bind_null(7); - return false; + rc = statements["stock"].step(); + + if(rc != Sqlite.DONE) + throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc); } - public bool new_product(uint64 id, string name, int memberprice, int guestprice) { + public void new_product(uint64 id, string name, int memberprice, int guestprice) throws DatabaseError { statements["product_create"].reset(); statements["product_create"].bind_text(1, @"$id"); statements["product_create"].bind_text(2, name); @@ -550,14 +455,13 @@ public class Database { int rc = statements["product_create"].step(); if(rc != Sqlite.DONE) { - warning("[internal error: %d]".printf(rc)); - return false; + throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc); } - return new_price(id, 0, memberprice, guestprice); + new_price(id, 0, memberprice, guestprice); } - public bool new_price(uint64 product, int64 timestamp, int memberprice, int guestprice) { + public void new_price(uint64 product, int64 timestamp, int memberprice, int guestprice) throws DatabaseError { statements["price_create"].reset(); statements["price_create"].bind_text(1, @"$product"); statements["price_create"].bind_int64(2, timestamp); @@ -566,11 +470,8 @@ public class Database { int rc = statements["price_create"].step(); if(rc != Sqlite.DONE) { - warning("[internal error: %d]".printf(rc)); - return false; + throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc); } - - return true; } public bool check_user_password(int32 user, string password) { @@ -587,7 +488,7 @@ public class Database { } } - public void set_user_password(int32 user, string password) { + public void set_user_password(int32 user, string password) throws DatabaseError { var pwhash = Checksum.compute_for_string(ChecksumType.SHA256, password); int rc; @@ -596,7 +497,7 @@ public class Database { statements["user_auth_create"].bind_int(1, user); rc = statements["user_auth_create"].step(); if(rc != Sqlite.DONE) - error("[internal error: %d]".printf(rc)); + throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc); /* set password */ statements["password_set"].reset(); @@ -604,36 +505,37 @@ public class Database { statements["password_set"].bind_int(2, user); rc = statements["password_set"].step(); if(rc != Sqlite.DONE) - error("[internal error: %d]".printf(rc)); + throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc); } - public void set_sessionid(int user, string sessionid) { + public void set_sessionid(int user, string sessionid) throws DatabaseError { statements["session_set"].reset(); statements["session_set"].bind_text(1, sessionid); statements["session_set"].bind_int(2, user); int rc = statements["session_set"].step(); if(rc != Sqlite.DONE) - error("[internal error: %d]".printf(rc)); + throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc); } - public int get_user_by_sessionid(string sessionid) throws WebSessionError { + public int get_user_by_sessionid(string sessionid) throws DatabaseError { statements["session_get"].reset(); statements["session_get"].bind_text(1, sessionid); if(statements["session_get"].step() == Sqlite.ROW) { return statements["session_get"].column_int(0); } else { - throw new WebSessionError.SESSION_NOT_FOUND("No such session available in database!"); + throw new DatabaseError.SESSION_NOT_FOUND("No such session available in database!"); } } - public UserInfo get_user_info(int user) { + public UserInfo get_user_info(int user) throws DatabaseError { var result = UserInfo(); statements["userinfo"].reset(); statements["userinfo"].bind_int(1, user); + int rc = statements["userinfo"].step(); - if(statements["userinfo"].step() == Sqlite.ROW) { + if(rc == Sqlite.ROW) { result.id = user; result.firstname = statements["userinfo"].column_text(0); result.lastname = statements["userinfo"].column_text(1); @@ -643,12 +545,16 @@ public class Database { result.postcode = statements["userinfo"].column_int(5); result.city = statements["userinfo"].column_text(6); result.pgp = statements["userinfo"].column_text(7); + } else if(rc == Sqlite.DONE) { + throw new DatabaseError.USER_NOT_FOUND("user not found"); + } else { + throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc); } return result; } - public UserAuth get_user_auth(int user) { + public UserAuth get_user_auth(int user) throws DatabaseError { var result = UserAuth(); result.id = user; result.disabled = false; @@ -656,27 +562,33 @@ public class Database { statements["userauth"].reset(); statements["userauth"].bind_int(1, user); - if(statements["userauth"].step() == Sqlite.ROW) { + int rc = statements["userauth"].step(); + + if(rc == Sqlite.ROW) { result.disabled = statements["userauth"].column_int(0) == 1; result.superuser = statements["userauth"].column_int(1) == 1; + } else if(rc == Sqlite.DONE) { + throw new DatabaseError.USER_NOT_FOUND("user not found"); + } else { + throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc); } return result; } - public string get_username(int user) throws WebSessionError { + public string get_username(int user) throws DatabaseError { statements["username"].reset(); statements["username"].bind_int(1, user); if(statements["username"].step() == Sqlite.ROW) { return statements["username"].column_text(0)+" "+statements["username"].column_text(1); } else { - throw new WebSessionError.USER_NOT_FOUND("No such user available in database!"); + throw new DatabaseError.USER_NOT_FOUND("No such user available in database!"); } } - public Gee.List<InvoiceEntry?> get_invoice(int user, int64 from=0, int64 to=-1) { - var result = new Gee.ArrayList<InvoiceEntry?>(); + public InvoiceEntry[] get_invoice(int user, int64 from=0, int64 to=-1) throws DatabaseError { + InvoiceEntry[] result = {}; if(to == -1) { to = time_t(); @@ -686,37 +598,44 @@ public class Database { statements["invoice"].bind_int(1, user); statements["invoice"].bind_int64(2, from); statements["invoice"].bind_int64(3, to); + int rc = statements["invoice"].step(); - while(statements["invoice"].step() == Sqlite.ROW) { + while(rc == Sqlite.ROW) { InvoiceEntry entry = {}; entry.timestamp = statements["invoice"].column_int64(0); entry.product.ean = uint64.parse(statements["invoice"].column_text(1)); entry.product.name = statements["invoice"].column_text(2); entry.price = statements["invoice"].column_int(3); - result.add(entry); + result += entry; + + rc = statements["invoice"].step(); + } + + if(rc != Sqlite.DONE) { + throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc); } return result; } - public DateTime get_first_purchase(int user) { + public int64 get_first_purchase(int user) { statements["purchase_first"].reset(); statements["purchase_first"].bind_int(1, user); if(statements["purchase_first"].step() == Sqlite.ROW) - return new DateTime.from_unix_utc(statements["purchase_first"].column_int64(0)); + return statements["purchase_first"].column_int64(0); else - return new DateTime.from_unix_utc(0); + return 0; } - public DateTime get_last_purchase(int user) { + public int64 get_last_purchase(int user) { statements["purchase_last"].reset(); statements["purchase_last"].bind_int(1, user); if(statements["purchase_last"].step() == Sqlite.ROW) - return new DateTime.from_unix_utc(statements["purchase_last"].column_int64(0)); + return statements["purchase_last"].column_int64(0); else - return new DateTime.from_unix_utc(0); + return 0; } public StatsInfo get_stats_info() { @@ -794,17 +713,17 @@ public class Database { return result; } - public Gee.List<int> get_member_ids() { - var result = new Gee.ArrayList<int>(); + public int[] get_member_ids() { + int[] result = {}; statements["user_get_ids"].reset(); while(statements["user_get_ids"].step() == Sqlite.ROW) - result.add(statements["user_get_ids"].column_int(0)); + result += statements["user_get_ids"].column_int(0); return result; } - public void user_disable(int user, bool value) { + public void user_disable(int user, bool value) throws DatabaseError { int rc; /* create user auth line if not existing */ @@ -812,7 +731,7 @@ public class Database { statements["user_auth_create"].bind_int(1, user); rc = statements["user_auth_create"].step(); if(rc != Sqlite.DONE) - error("[internal error: %d]".printf(rc)); + throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc); /* set disabled flag */ statements["user_disable"].reset(); @@ -820,10 +739,10 @@ public class Database { statements["user_disable"].bind_int(2, user); rc = statements["user_disable"].step(); if(rc != Sqlite.DONE) - error("[internal error: %d]".printf(rc)); + throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc); } - public void user_replace(UserInfo u) { + public void user_replace(UserInfo u) throws DatabaseError { statements["user_replace"].reset(); statements["user_replace"].bind_int(1, u.id); statements["user_replace"].bind_text(2, u.email); @@ -837,13 +756,24 @@ public class Database { int rc = statements["user_replace"].step(); if(rc != Sqlite.DONE) - error("[internal error: %d]".printf(rc)); + throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc); } - public bool user_is_disabled(int user) { + public bool user_is_disabled(int user) throws DatabaseError { return get_user_auth(user).disabled; } + public bool user_exists(int user) throws DatabaseError { + if(user in get_member_ids()) + return true; + return false; + } + + public bool user_equals(UserInfo u) throws DatabaseError { + var dbu = get_user_info(u.id); + return u.equals(dbu); + } + public int64 get_timestamp_of_last_purchase() { statements["last_timestamp"].reset(); if(statements["last_timestamp"].step() != Sqlite.ROW) @@ -851,10 +781,10 @@ public class Database { return statements["last_timestamp"].column_int64(0); } - public Gee.List<Supplier?> get_supplier_list() { - var result = new Gee.ArrayList<Supplier?>(); - statements["supplier_list"].reset(); + public Supplier[] get_supplier_list() { + Supplier[] result = {}; + statements["supplier_list"].reset(); while(statements["supplier_list"].step() == Sqlite.ROW) { Supplier entry = { statements["supplier_list"].column_int64(0), @@ -866,7 +796,7 @@ public class Database { statements["supplier_list"].column_text(6) }; - result.add(entry); + result += entry; } return result; @@ -899,7 +829,7 @@ public class Database { return result; } - public bool add_supplier(string name, string postal_code, string city, string street, string phone, string website) { + public void add_supplier(string name, string postal_code, string city, string street, string phone, string website) throws DatabaseError { statements["supplier_add"].reset(); statements["supplier_add"].bind_text(1, name); statements["supplier_add"].bind_text(2, postal_code); @@ -910,10 +840,7 @@ public class Database { int rc = statements["supplier_add"].step(); if(rc != Sqlite.DONE) { - warning("[internal error: %d]".printf(rc)); - return false; + throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc); } - - return true; } } diff --git a/src/database/db-interface.vala b/src/database/db-interface.vala new file mode 100644 index 0000000..da95eb7 --- /dev/null +++ b/src/database/db-interface.vala @@ -0,0 +1,148 @@ +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +[DBus (name = "io.mainframe.shopsystem.Database")] +public interface Database : Object { + public abstract StockEntry[] get_stock() throws IOError; + public abstract PriceEntry[] get_prices(uint64 product) throws IOError; + public abstract RestockEntry[] get_restocks(uint64 product) throws IOError; + public abstract bool buy(int32 user, uint64 article) throws IOError, DatabaseError; + public abstract string get_product_name(uint64 article) throws IOError, DatabaseError; + public abstract int get_product_amount(uint64 article) throws IOError, DatabaseError; + public abstract Price get_product_price(int user, uint64 article) throws IOError, DatabaseError; + public abstract bool undo(int32 user) throws IOError, DatabaseError; + public abstract bool restock(int user, uint64 product, uint amount, uint price, int supplier, int64 best_before_date) throws IOError, DatabaseError; + public abstract bool new_product(uint64 id, string name, int memberprice, int guestprice) throws IOError, DatabaseError; + public abstract bool new_price(uint64 product, int64 timestamp, int memberprice, int guestprice) throws IOError, DatabaseError; + public abstract bool check_user_password(int32 user, string password) throws IOError; + public abstract void set_user_password(int32 user, string password) throws IOError, DatabaseError; + public abstract void set_sessionid(int user, string sessionid) throws IOError, DatabaseError; + public abstract int get_user_by_sessionid(string sessionid) throws IOError, DatabaseError; + public abstract UserInfo get_user_info(int user) throws IOError, DatabaseError; + public abstract UserAuth get_user_auth(int user) throws IOError, DatabaseError; + public abstract string get_username(int user) throws IOError, DatabaseError; + public abstract InvoiceEntry[] get_invoice(int user, int64 from=0, int64 to=-1) throws IOError, DatabaseError; + public abstract int64 get_first_purchase(int user) throws IOError; + public abstract int64 get_last_purchase(int user) throws IOError; + public abstract StatsInfo get_stats_info() throws IOError; + public abstract int[] get_member_ids() throws IOError; + public abstract void user_disable(int user, bool value) throws IOError, DatabaseError; + public abstract void user_replace(UserInfo u) throws IOError, DatabaseError; + public abstract bool user_is_disabled(int user) throws IOError, DatabaseError; + public abstract bool user_exists(int user) throws IOError, DatabaseError; + public abstract bool user_equals(UserInfo u) throws IOError, DatabaseError; + public abstract int64 get_timestamp_of_last_purchase() throws IOError; + public abstract Supplier[] get_supplier_list() throws IOError; + public abstract Supplier get_supplier(int id) throws IOError; + public abstract bool add_supplier(string name, string postal_code, string city, string street, string phone, string website) throws IOError, DatabaseError; +} + +public struct StockEntry { + public string id; + public string name; + public int amount; + public string memberprice; + public string guestprice; +} + +public struct PriceEntry { + public int64 valid_from; + public Price memberprice; + public Price guestprice; +} + +public struct RestockEntry { + public int64 timestamp; + public int amount; + public string price; + public int supplier; + public int64 best_before_date; +} + +public struct Supplier { + public int64 id; + public string name; + public string postal_code; + public string city; + public string street; + public string phone; + public string website; +} + +public struct UserInfo { + public int id; + public string firstname; + public string lastname; + public string email; + public string gender; + public string street; + public int postcode; + public string city; + public string pgp; + + public bool equals(UserInfo x) { + if(id != x.id) return false; + if(firstname != x.firstname) return false; + if(lastname != x.lastname) return false; + if(email != x.email) return false; + if(gender != x.gender) return false; + if(street != x.street) return false; + if(postcode != x.postcode) return false; + if(city != x.city) return false; + if(pgp != x.pgp) return false; + + return true; + } +} + +public struct UserAuth { + public int id; + public bool disabled; + public bool superuser; +} + +public struct Product { + public uint64 ean; + public string name; +} + +public struct InvoiceEntry { + public int64 timestamp; + Product product; + Price price; +} + +public struct StatsInfo { + public int count_articles; + public int count_users; + public Price stock_value; + public Price sales_total; + public Price profit_total; + public Price sales_today; + public Price profit_today; + public Price sales_this_month; + public Price profit_this_month; + public Price sales_per_day; + public Price profit_per_day; + public Price sales_per_month; + public Price profit_per_month; +} + +public errordomain DatabaseError { + INTERNAL_ERROR, + PRODUCT_NOT_FOUND, + SESSION_NOT_FOUND, + USER_NOT_FOUND +} diff --git a/src/database/main.vala b/src/database/main.vala new file mode 100644 index 0000000..676e960 --- /dev/null +++ b/src/database/main.vala @@ -0,0 +1,44 @@ +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +public static void write_to_log(string message, ...) { + /* TODO: send message via DBus? Replace some write_to_log by throwing an error? */ +} + +DataBase db; + +public static int main(string[] args) { + db = new DataBase("../../shop.db"); + + Bus.own_name( + BusType.SESSION, + "io.mainframe.shopsystem.Database", + BusNameOwnerFlags.NONE, + on_bus_aquired, + () => {}, + () => stderr.printf("Could not aquire name\n")); + + new MainLoop().run(); + + return 0; +} + +void on_bus_aquired(DBusConnection con) { + try { + con.register_object("/io/mainframe/shopsystem/database", db); + } catch(IOError e) { + stderr.printf("Could not register service\n"); + } +} diff --git a/src/main.vala b/src/main.vala deleted file mode 100644 index 67f00ff..0000000 --- a/src/main.vala +++ /dev/null @@ -1,131 +0,0 @@ -/* Copyright 2012, Sebastian Reichel <sre@ring0.de> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -public Device dev; -public Database db; -public AudioPlayer audio; -public CSVMemberFile csvimport; -public ScannerSession localsession; -public MainLoop loop; -public PGPKeyArchive pgp; -public KeyFile cfg; -public CursesUI ui; - -const OptionEntry[] option_entries = { - { "version", 'v', OptionFlags.IN_MAIN, OptionArg.NONE, ref opt_version, "output version information and exit", null }, - {null} -}; - -/* parameters */ -static bool opt_version; - -public static int main(string[] args) { - /* parse parameters from shell */ - var context = new OptionContext("- KtT Shop System"); - context.set_help_enabled(true); - context.add_main_entries(option_entries, "shop"); - context.add_group(Gst.init_get_option_group()); - - try { - context.parse(ref args); - } catch(OptionError e) { - stderr.puts(e.message + "\n"); - return 1; - } - - if(opt_version) { - stdout.puts("KtT Shop System 0.1\n"); - return 0; - } - - /* handle unix signals */ - Unix.signal_add(Posix.SIGTERM, handle_signals); - Unix.signal_add(Posix.SIGINT, handle_signals); - - try { - cfg = new KeyFile(); - cfg.load_from_file("ktt-shopsystem.cfg", KeyFileFlags.NONE); - } catch(Error e) { - error("Could not load configuration file: %s", e.message); - } - - string devicefile = ""; - try { - devicefile = cfg.get_string("SERIAL", "device"); - } catch(KeyFileError e) { - stderr.puts("Please specify serial device in the configuration file!\n"); - return 1; - } - - dev = new Device(devicefile, 9600, 8, 1); - db = new Database("shop.db"); - audio = new AudioPlayer(); - loop = new MainLoop(); - localsession = new ScannerSession(); - - pgp = new PGPKeyArchive(cfg); - - dev.received_barcode.connect((data) => { - if(localsession.interpret(data)) - dev.blink(10); - }); - - ui = new CursesUI(); - - while(!check_valid_time()) { - write_to_log("Invalid System Time! Retry in 1 minute..."); - Posix.sleep(60); - } - - write_to_log("KtT Shop System has been started"); - audio.play_system("startup.ogg"); - - /* attach webserver to mainloop */ - new WebServer(); - - /* run mainloop */ - loop.run(); - - write_to_log("Stopping Shop System"); - audio.play_system("shutdown.ogg"); - - /* we need to run the mainloop to play audio */ - audio.end_of_stream.connect(() => { loop.quit(); }); - loop.run(); - - /* explicitly call destructors */ - dev = null; - db = null; - audio = null; - ui.exit(); - - return 0; -} - -public bool check_valid_time() { - return time_t() > db.get_timestamp_of_last_purchase(); -} - -public void write_to_log(string format, ...) { - var arguments = va_list(); - var message = format.vprintf(arguments); - - ui.log(message); -} - -bool handle_signals() { - loop.quit(); - return false; -} diff --git a/src/pdf-invoice/Makefile b/src/pdf-invoice/Makefile index 2a5d2a4..cc6db94 100644 --- a/src/pdf-invoice/Makefile +++ b/src/pdf-invoice/Makefile @@ -1,9 +1,12 @@ all: pdf-invoice -pdf-invoice: pdf-invoice.vala ../price.vapi - valac --pkg pangocairo --pkg posix --pkg gio-2.0 $^ +pdf-invoice: main.vala pdf-invoice.vala pdf-invoice-interface.vala ../price.vapi + valac -g -o $@ --pkg pangocairo --pkg librsvg-2.0 --pkg posix --pkg gdk-2.0 --pkg gio-2.0 $^ + +test: pdf-invoice-interface.vala test.vala ../price.vapi + valac -o $@ --pkg gio-2.0 $^ clean: - rm -rf pdf-invoice + rm -rf pdf-invoice test .PHONY: all clean diff --git a/src/pdf-invoice/main.vala b/src/pdf-invoice/main.vala new file mode 100644 index 0000000..76b03c6 --- /dev/null +++ b/src/pdf-invoice/main.vala @@ -0,0 +1,36 @@ +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +public static int main(string[] args) { + Bus.own_name( + BusType.SESSION, + "io.mainframe.shopsystem.InvoicePDF", + BusNameOwnerFlags.NONE, + on_bus_aquired, + () => {}, + () => stderr.printf("Could not aquire name\n")); + + new MainLoop().run(); + + return 0; +} + +void on_bus_aquired(DBusConnection conn) { + try { + conn.register_object("/io/mainframe/shopsystem/invoicepdf", new InvoicePDF()); + } catch(IOError e) { + stderr.printf("Could not register service\n"); + } +} diff --git a/src/pdf-invoice/pdf-invoice-interface.vala b/src/pdf-invoice/pdf-invoice-interface.vala new file mode 100644 index 0000000..d2c04d9 --- /dev/null +++ b/src/pdf-invoice/pdf-invoice-interface.vala @@ -0,0 +1,54 @@ +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +[DBus (name = "io.mainframe.shopsystem.InvoicePDFError")] +public errordomain InvoicePDFError { + /* missing invoice data */ + NO_INVOICE_DATA, + NO_INVOICE_DATE, + NO_INVOICE_ID, + NO_INVOICE_RECIPIENT, + + /* data not supported by renderer */ + ARTICLE_NAME_TOO_LONG, + PRICE_TOO_HIGH, + TOO_FAR_IN_THE_FUTURE +} + +public struct InvoiceRecipient { + public string firstname; + public string lastname; + public string street; + public string postal_code; + public string city; + public string gender; +} + +public struct InvoiceEntry { + int timestamp; + string article; + Price price; +} + +[DBus (name = "io.mainframe.shopsystem.InvoicePDF")] +public interface PDFInvoice : Object { + public abstract string invoice_id { set; owned get; } + public abstract int64 invoice_date { set; owned get; } + public abstract InvoiceRecipient invoice_recipient { set; owned get; } + public abstract InvoiceEntry[] invoice_entries { set; owned get; } + + public abstract uint8[] generate() throws IOError, InvoicePDFError; + public abstract void clear() throws IOError; +} diff --git a/src/pdf-invoice/pdf-invoice.vala b/src/pdf-invoice/pdf-invoice.vala index 92598f6..095dcc6 100644 --- a/src/pdf-invoice/pdf-invoice.vala +++ b/src/pdf-invoice/pdf-invoice.vala @@ -13,35 +13,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -[DBus (name = "io.mainframe.shopsystem.InvoicePDFError")] -public errordomain InvoicePDFError { - /* missing invoice data */ - NO_INVOICE_DATA, - NO_INVOICE_DATE, - NO_INVOICE_ID, - NO_INVOICE_RECIPIENT, - - /* data not supported by renderer */ - ARTICLE_NAME_TOO_LONG, - PRICE_TOO_HIGH, - TOO_FAR_IN_THE_FUTURE -} - -public struct InvoiceRecipient { - public string firstname; - public string lastname; - public string street; - public string postal_code; - public string city; - public string gender; -} - -public struct InvoiceEntry { - int timestamp; - string article; - Price price; -} - [DBus (name = "io.mainframe.shopsystem.InvoicePDF")] public class InvoicePDF { /* A4 sizes (in points, 72 DPI) */ @@ -49,10 +20,10 @@ public class InvoicePDF { private const double height = 841.88976; /* 297mm */ /* invoice content, which should appear in the PDF */ - public string invoice_id { set; get; } + public string invoice_id { set; owned get; } public int64 invoice_date { set; get; } - public InvoiceRecipient invoice_recipient { set; get; } - public InvoiceEntry[] invoice_entries { set; get; } + public InvoiceRecipient invoice_recipient { set; owned get; } + public InvoiceEntry[] invoice_entries { set; owned get; } /* pdf data */ private uint8[] data; @@ -77,29 +48,27 @@ public class InvoicePDF { }; public InvoicePDF() { + clear(); + } + + private void render_svg(Cairo.Context ctx, string file) { + var svg = new Rsvg.Handle.from_file(file); + svg.render_cairo(ctx); } private void draw_footer(Cairo.Context ctx) { - /* TODO: get path from config file, support svg */ - var footer = new Cairo.ImageSurface.from_png("../../invoice/footer-line.png"); - ctx.set_source_surface(footer, 0, 817); - ctx.paint(); + ctx.save(); + ctx.translate(-20, 818); + ctx.scale(1.42, 1.42); + render_svg(ctx, "../../invoice/footer-line.svg"); + ctx.restore(); } private void draw_logo(Cairo.Context ctx) { - /* TODO: get path from config file, support svg */ - var logo = new Cairo.ImageSurface.from_png("../../invoice/logo.png"); - - var pattern = new Cairo.Pattern.for_surface(logo); - Cairo.Matrix scaler; - pattern.get_matrix(out scaler); - scaler.scale(1.41,1.41); - scaler.translate(-364.5,-22.5); - pattern.set_matrix(scaler); - pattern.set_filter(Cairo.Filter.BEST); - - ctx.set_source(pattern); - ctx.paint(); + ctx.save(); + ctx.translate(366,25); + render_svg(ctx, "../../invoice/logo.svg"); + ctx.restore(); } private void draw_address(Cairo.Context ctx) { @@ -661,29 +630,14 @@ public class InvoicePDF { public void clear() { invoice_date = 0; invoice_id = ""; - invoice_recipient = {}; + invoice_recipient = { + "", + "", + "", + "", + "", + "", + }; invoice_entries = null; } } - -public static int main(string[] args) { - Bus.own_name( - BusType.SESSION, - "io.mainframe.shopsystem.InvoicePDF", - BusNameOwnerFlags.NONE, - on_bus_aquired, - () => {}, - () => stderr.printf ("Could not aquire name\n")); - - new MainLoop ().run (); - - return 0; -} - -void on_bus_aquired(DBusConnection conn) { - try { - conn.register_object ("/io/mainframe/invoicepdf", new InvoicePDF()); - } catch (IOError e) { - stderr.printf ("Could not register service\n"); - } -} diff --git a/src/pdf-invoice/test.vala b/src/pdf-invoice/test.vala new file mode 100644 index 0000000..f9d21f6 --- /dev/null +++ b/src/pdf-invoice/test.vala @@ -0,0 +1,47 @@ +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +public static int main(string args[]) { + PDFInvoice invoice = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.InvoicePDF", "/io/mainframe/shopsystem/invoicepdf"); + + InvoiceRecipient r = { + "Max", + "Mustermann", + "Foobar Straße 42", + "31337", + "Entenhausen", + "masculinum" + }; + + InvoiceEntry e1 = { + 1364271520, + "Club Mate", + 2342 + }; + + /* set invoice data */ + invoice.invoice_id = "TEST"; + invoice.invoice_date = 1364271524; + invoice.invoice_recipient = r; + invoice.invoice_entries = {e1}; + + /* generate pdf */ + var pdfdata = invoice.generate(); + + /* write pdf into file */ + FileUtils.set_contents("test.pdf", (string) pdfdata, pdfdata.length); + + return 0; +} diff --git a/src/pgp/Makefile b/src/pgp/Makefile new file mode 100644 index 0000000..6bcb535 --- /dev/null +++ b/src/pgp/Makefile @@ -0,0 +1,9 @@ +all: pgp + +pgp: main.vala pgp.vala pgp-interface.vala ../config/config-interface.vala + valac -o $@ --vapidir ../../vapi -X -lgpgme --pkg gpgme --pkg gio-2.0 --pkg libarchive $^ + +clean: + rm -rf pgp + +.PHONY: all clean diff --git a/src/pgp/main.vala b/src/pgp/main.vala new file mode 100644 index 0000000..f95b6f7 --- /dev/null +++ b/src/pgp/main.vala @@ -0,0 +1,53 @@ +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +public static void write_to_log(string message, ...) { + /* TODO: send message via DBus? Replace some write_to_log by throwing an error? */ +} + +PGPKeyArchive pgp; +Config cfg; + +public static int main(string[] args) { + try { + cfg = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.Config", "/io/mainframe/shopsystem/config"); + pgp = new PGPKeyArchive(cfg.get_string("PGP", "keyring")); + } catch(IOError e) { + error("IOError: %s\n", e.message); + } catch(KeyFileError e) { + error("Config Error: %s\n", e.message); + } + + + Bus.own_name( + BusType.SESSION, + "io.mainframe.shopsystem.PGP", + BusNameOwnerFlags.NONE, + on_bus_aquired, + () => {}, + () => stderr.printf("Could not aquire name\n")); + + new MainLoop().run(); + + return 0; +} + +void on_bus_aquired(DBusConnection con) { + try { + con.register_object("/io/mainframe/shopsystem/pgp", pgp); + } catch(IOError e) { + stderr.printf("Could not register service\n"); + } +} diff --git a/src/pgp/pgp-interface.vala b/src/pgp/pgp-interface.vala new file mode 100644 index 0000000..62bfe67 --- /dev/null +++ b/src/pgp/pgp-interface.vala @@ -0,0 +1,21 @@ +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +[DBus (name = "io.mainframe.shopsystem.PGP")] +public interface PGP : Object { + public abstract string[] import_archive(uint8[] data) throws IOError; + public abstract string[] list_keys() throws IOError; + public abstract string get_key(string fingerprint) throws IOError; +} diff --git a/src/admin.vala b/src/pgp/pgp.vala index de123e1..bb48c61 100644 --- a/src/admin.vala +++ b/src/pgp/pgp.vala @@ -1,4 +1,4 @@ -/* Copyright 2012, Sebastian Reichel <sre@ring0.de> +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -13,88 +13,24 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -public class CSVMemberFile { - private UserInfo[] members; - - public Gee.List<int> missing_unblocked_members() { - var result = new Gee.ArrayList<int>(); - var dbusers = db.get_member_ids(); - - foreach(var u in dbusers) { - bool found=false; - foreach(var m in members) { - if(u == m.id) { - found=true; - break; - } - } - - if(!found) { - if(!db.user_is_disabled(u)) - result.add(u); - } - } - - return result; - } - - private string[] csv_split(string line) { - return /;(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/.split(line); - } - - private string csv_value(string value) { - if(value[0] == '"' && value[value.length-1] == '"') - return value.substring(1,value.length-2); - else - return value; - } - - public CSVMemberFile(string data) { - foreach(var line in data.split("\n")) { - var linedata = csv_split(line); - if(linedata.length >= 9) { - var m = UserInfo(); - m.id = int.parse(csv_value(linedata[0])); - m.email = csv_value(linedata[1]); - m.firstname = csv_value(linedata[2]); - m.lastname = csv_value(linedata[3]); - m.street = csv_value(linedata[4]); - m.postcode = int.parse(csv_value(linedata[5])); - m.city = csv_value(linedata[6]); - m.gender = csv_value(linedata[7]) == "m" ? "masculinum" : csv_value(linedata[7]) == "w" ? "femininum" : "unknown"; - m.pgp = csv_value(linedata[8]); - if(csv_value(linedata[0]) != "EXTERNEMITGLIEDSNUMMER") - members += m; - } - } - } - - public UserInfo[] get_members() { - return members; - } -} - +[DBus (name = "io.mainframe.shopsystem.PGP")] public class PGPKeyArchive { private string keyring; private GPG.Context gpg; - public PGPKeyArchive(KeyFile config) { + public PGPKeyArchive(string keyring) { /* check version (important!) */ GPG.check_version(); /* initialize default context */ GPG.Context.Context(out gpg); - try { - keyring = config.get_string("PGP", "keyring"); - - /* remove quotes */ - if(keyring.has_prefix("\"") && keyring.has_suffix("\"")) - keyring = keyring.substring(1,keyring.length-2); - } catch(KeyFileError e) { - write_to_log("KeyFileError: %s", e.message); - return; - } + /* TODO TODO TODO */ +#if 0 + if(keyring.has_prefix("\"") && keyring.has_suffix("\"")) + this.keyring = keyring.substring(1,keyring.length-2); +#endif + this.keyring = keyring; /* TODO: check existence of keyring */ diff --git a/src/scanner-session/Makefile b/src/scanner-session/Makefile new file mode 100644 index 0000000..ea91d3a --- /dev/null +++ b/src/scanner-session/Makefile @@ -0,0 +1,9 @@ +all: scanner-session + +scanner-session: main.vala scannersession.vala scannersession-interface.vala ../database/db-interface.vala ../serial-device/serial-device-interface.vala ../audio/audio-interface.vala ../price.vapi + valac -o $@ --pkg gio-2.0 $^ + +clean: + rm -rf scanner-session + +.PHONY: all clean diff --git a/src/scanner-session/main.vala b/src/scanner-session/main.vala new file mode 100644 index 0000000..11562e1 --- /dev/null +++ b/src/scanner-session/main.vala @@ -0,0 +1,38 @@ +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +ScannerSessionImplementation session; + +public static int main(string[] args) { + Bus.own_name( + BusType.SESSION, + "io.mainframe.shopsystem.ScannerSession", + BusNameOwnerFlags.NONE, + on_bus_aquired, + () => {}, + () => stderr.printf("Could not aquire name\n")); + + new MainLoop().run(); + + return 0; +} + +void on_bus_aquired(DBusConnection con) { + try { + con.register_object("/io/mainframe/shopsystem/scanner_session", session); + } catch(IOError e) { + stderr.printf("Could not register service\n"); + } +} diff --git a/src/scanner-session/scannersession-interface.vala b/src/scanner-session/scannersession-interface.vala new file mode 100644 index 0000000..0f81dd4 --- /dev/null +++ b/src/scanner-session/scannersession-interface.vala @@ -0,0 +1,25 @@ +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +[DBus (name = "io.mainframe.shopsystem.ScannerSession")] +public interface ScannerSession : Object { + public abstract signal void msg(MessageType type, string message); +} + +public enum MessageType { + INFO, + WARNING, + ERROR +} diff --git a/src/scannersession.vala b/src/scanner-session/scannersession.vala index 9dbe3d3..6926ba9 100644 --- a/src/scannersession.vala +++ b/src/scanner-session/scannersession.vala @@ -1,4 +1,4 @@ -/* Copyright 2012, Sebastian Reichel <sre@ring0.de> +/* Copyright 2012-2013, Sebastian Reichel <sre@ring0.de> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -13,43 +13,45 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -public class ScannerSession { - public int user { - get; - private set; - default = 0; - } - public string name { - get; - private set; - default = "Guest"; - } - public bool logged_in { - get; - private set; - default = false; - } - public bool disabled { - get; - private set; - default = false; +[DBus (name = "io.mainframe.shopsystem.ScannerSession")] +public class ScannerSessionImplementation { + private int user = 0; + private string name = "Guest"; + private bool logged_in = false; + private bool disabled = false; + private string theme = "beep"; + + private Database db; + private AudioPlayer audio; + + public signal void msg(MessageType type, string message); + + public ScannerSessionImplementation() { + try { + db = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.Database", "/io/mainframe/shopsystem/database"); + audio = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.AudioPlayer", "/io/mainframe/shopsystem/audio"); + } catch(IOError e) { + error("IOError: %s\n", e.message); + } } - public string theme { - get; - private set; - default = "beep"; + + private void send_message(MessageType type, string format, ...) { + var arguments = va_list(); + var message = format.vprintf(arguments); + + msg(type, message); } - public void logout() { + private void logout() { logged_in = false; } - public bool login(int user) { + private bool login(int user) { this.user = user; try { this.name = db.get_username(user); this.disabled = db.get_user_auth(user).disabled; - } catch(WebSessionError e) { + } catch(DatabaseError e) { return false; } this.logged_in = true; @@ -58,10 +60,7 @@ public class ScannerSession { return true; } - public ScannerSession() { - } - - public bool interpret(string scannerdata) { + private bool interpret(string scannerdata) { if(scannerdata.has_prefix("USER ")) { string str_id = scannerdata.substring(5); int32 id = int.parse(str_id); @@ -69,43 +68,43 @@ public class ScannerSession { /* check if scannerdata has valid format */ if(scannerdata != "USER %d".printf(id)) { audio.play_system("error.ogg"); - write_to_log("Error: Invalid User ID: %s", scannerdata); + send_message(MessageType.ERROR, "Invalid User ID: %s", scannerdata); return false; } if(logged_in) { - write_to_log("Warning: Last user forgot to logout"); + send_message(MessageType.WARNING, "Last user forgot to logout"); logout(); } if(login(id)) { audio.play_user(theme, "login"); - write_to_log("Login: %s (%d)", name, user); + send_message(MessageType.INFO, "Login: %s (%d)", name, user); return true; } else { audio.play_system("error.ogg"); - write_to_log("Error: Login failed (User ID = %d)", id); + send_message(MessageType.ERROR, "Login failed (User ID = %d)", id); return false; } } else if(scannerdata == "GUEST") { if(logged_in) { - write_to_log("Warning: Last user forgot to logout"); + send_message(MessageType.WARNING, "Last user forgot to logout"); logout(); } if(login(0)) { audio.play_user(theme, "login"); - write_to_log("Login: %s (%d)", name, user); + send_message(MessageType.INFO, "Login: %s (%d)", name, user); return true; } else { audio.play_system("error.ogg"); - write_to_log("Error: Login failed (User ID = 0)"); + send_message(MessageType.ERROR, "Login failed (User ID = 0)"); return false; } } else if(scannerdata == "UNDO") { if(!logged_in) { audio.play_system("error.ogg"); - write_to_log("Error: Can't undo if not logged in!"); + send_message(MessageType.ERROR, "Can't undo if not logged in!"); return false; } else { if(db.undo(user)) { @@ -113,14 +112,14 @@ public class ScannerSession { return true; } else { audio.play_user(theme, "error"); - write_to_log("Error: Couldn't undo last purchase!"); + send_message(MessageType.ERROR, "Couldn't undo last purchase!"); return false; } } } else if(scannerdata == "LOGOUT") { if(logged_in) { audio.play_user(theme, "logout"); - write_to_log("Logout!"); + send_message(MessageType.INFO, "Logout!"); logout(); return true; } @@ -133,7 +132,7 @@ public class ScannerSession { /* check if scannerdata has valid format */ if(scannerdata != "%llu".printf(id) && scannerdata != "%08llu".printf(id) && scannerdata != "%013llu".printf(id)) { audio.play_user(theme, "error"); - write_to_log("Error: invalid product: %s", scannerdata); + send_message(MessageType.ERROR, "invalid product: %s", scannerdata); return false; } @@ -144,19 +143,19 @@ public class ScannerSession { var gprice = db.get_product_price(0, id); audio.play_system("error.ogg"); - write_to_log(@"article info: $name (Member: $mprice €, Guest: $gprice €)"); - write_to_log("Error: Login required for purchase!"); + send_message(MessageType.INFO, @"article info: $name (Member: $mprice €, Guest: $gprice €)"); + send_message(MessageType.ERROR, "Login required for purchase!"); return false; } if(db.buy(user, id)) { var price = db.get_product_price(user, id); audio.play_user(theme, "purchase"); - write_to_log(@"article bought: $name ($price €)"); + send_message(MessageType.INFO, @"article bought: $name ($price €)"); return true; } else { audio.play_user(theme, "error"); - write_to_log("Error: purchase failed!"); + send_message(MessageType.ERROR, "purchase failed!"); return false; } } diff --git a/src/serial-device/Makefile b/src/serial-device/Makefile new file mode 100644 index 0000000..952b3a1 --- /dev/null +++ b/src/serial-device/Makefile @@ -0,0 +1,9 @@ +all: serial-device + +serial-device: main.vala serial-device.vala serial-device-interface.vala ../config/config-interface.vala + valac -o $@ --pkg linux --pkg posix --pkg gio-2.0 $^ + +clean: + rm -rf serial-device + +.PHONY: all clean diff --git a/src/serial-device/main.vala b/src/serial-device/main.vala new file mode 100644 index 0000000..e338842 --- /dev/null +++ b/src/serial-device/main.vala @@ -0,0 +1,47 @@ +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +Device dev; + +public static int main(string[] args) { + try { + Config cfg = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.Config", "/io/mainframe/shopsystem/config"); + dev = new Device(cfg.get_string("SERIAL", "device"), 9600, 8, 1); + } catch(IOError e) { + error("IOError: %s\n", e.message); + } catch(KeyFileError e) { + error("Config Error: %s\n", e.message); + } + + Bus.own_name( + BusType.SESSION, + "io.mainframe.shopsystem.SerialDevice", + BusNameOwnerFlags.NONE, + on_bus_aquired, + () => {}, + () => stderr.printf("Could not aquire name\n")); + + new MainLoop().run(); + + return 0; +} + +void on_bus_aquired(DBusConnection con) { + try { + con.register_object("/io/mainframe/shopsystem/device", dev); + } catch(IOError e) { + stderr.printf("Could not register service\n"); + } +} diff --git a/src/serial-device/serial-device-interface.vala b/src/serial-device/serial-device-interface.vala new file mode 100644 index 0000000..572e810 --- /dev/null +++ b/src/serial-device/serial-device-interface.vala @@ -0,0 +1,20 @@ +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +[DBus (name = "io.mainframe.shopsystem.SerialDevice")] +public interface SerialDevice : Object { + public abstract signal void received_barcode(string barcode); + public abstract void blink(uint duration) throws IOError; +} diff --git a/src/device.vala b/src/serial-device/serial-device.vala index 5d7fc09..76bb5b5 100644 --- a/src/device.vala +++ b/src/serial-device/serial-device.vala @@ -1,4 +1,4 @@ -/* Copyright 2012, Sebastian Reichel <sre@ring0.de> +/* Copyright 2012-2013, Sebastian Reichel <sre@ring0.de> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -13,12 +13,13 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +[DBus (name = "io.mainframe.shopsystem.SerialDevice")] public class Device { private Posix.termios newtio; private Posix.termios restoretio; - public int fd=-1; + private int fd=-1; private IOChannel io_read; - public int byterate; + private int byterate; private File lockfile; public signal void received_barcode(string barcode); diff --git a/src/ui/logo.vala b/src/ui/logo.vala deleted file mode 100644 index 5a94422..0000000 --- a/src/ui/logo.vala +++ /dev/null @@ -1,30 +0,0 @@ -using Curses; - -public class Logo { - Window win; - - public Logo() { - win = new Window(8, COLS - 2, 0, 1); - win.bkgdset(COLOR_PAIR(1) | Attribute.BOLD); - - win.addstr("\n"); - win.addstr(" _ ___ _____ ____ _ \n"); - win.addstr(" | |/ / ||_ _| / ___|| |__ ___ _ __ \n"); - win.addstr(" | ' /| __|| | \\___ \\| '_ \\ / _ \\| '_ \\ \n"); - win.addstr(" | . \\| |_ | | ___) | | | | (_) | |_) )\n"); - win.addstr(" |_|\\_\\\\__||_| |____/|_| |_|\\___/| .__/ \n"); - win.addstr(" |_| \n"); - - win.clrtobot(); - - win.box(0, 0); - - win.refresh(); - } - - public void redraw() { - win.touchwin(); - win.refresh(); - } - -} diff --git a/src/ui/status.vala b/src/ui/status.vala deleted file mode 100644 index db33820..0000000 --- a/src/ui/status.vala +++ /dev/null @@ -1,24 +0,0 @@ -using Curses; - -public class StatusPanel { - Window win; - - public StatusPanel() { - win = new Window(1, COLS - 2, LINES-1, 1); - win.bkgdset(COLOR_PAIR(2) | Attribute.BOLD); - - win.clrtobot(); - win.refresh(); - } - - public void set(string msg) { - win.mvaddstr(0,1, msg); - win.clrtobot(); - win.refresh(); - } - - public void redraw() { - win.touchwin(); - win.refresh(); - } -} diff --git a/src/web/Makefile b/src/web/Makefile new file mode 100644 index 0000000..cc9d77e --- /dev/null +++ b/src/web/Makefile @@ -0,0 +1,9 @@ +all: web + +web: main.vala web.vala websession.vala csv.vala template.vala ../database/db-interface.vala ../pgp/pgp-interface.vala ../price.vapi + valac -o $@ --vapidir=../../vapi --pkg gee-1.0 --pkg gio-2.0 --pkg libsoup-2.4 --pkg posix --pkg libarchive --pkg gpgme $^ + +clean: + rm -rf web + +.PHONY: all clean diff --git a/src/web/csv.vala b/src/web/csv.vala new file mode 100644 index 0000000..4e32a0a --- /dev/null +++ b/src/web/csv.vala @@ -0,0 +1,75 @@ +/* Copyright 2012, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +public class CSVMemberFile { + private UserInfo[] members; + + public Gee.List<int> missing_unblocked_members() { + var result = new Gee.ArrayList<int>(); + var dbusers = db.get_member_ids(); + + foreach(var u in dbusers) { + bool found=false; + foreach(var m in members) { + if(u == m.id) { + found=true; + break; + } + } + + if(!found) { + if(!db.user_is_disabled(u)) + result.add(u); + } + } + + return result; + } + + private string[] csv_split(string line) { + return /;(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/.split(line); + } + + private string csv_value(string value) { + if(value[0] == '"' && value[value.length-1] == '"') + return value.substring(1,value.length-2); + else + return value; + } + + public CSVMemberFile(string data) { + foreach(var line in data.split("\n")) { + var linedata = csv_split(line); + if(linedata.length >= 9) { + var m = UserInfo(); + m.id = int.parse(csv_value(linedata[0])); + m.email = csv_value(linedata[1]); + m.firstname = csv_value(linedata[2]); + m.lastname = csv_value(linedata[3]); + m.street = csv_value(linedata[4]); + m.postcode = int.parse(csv_value(linedata[5])); + m.city = csv_value(linedata[6]); + m.gender = csv_value(linedata[7]) == "m" ? "masculinum" : csv_value(linedata[7]) == "w" ? "femininum" : "unknown"; + m.pgp = csv_value(linedata[8]); + if(csv_value(linedata[0]) != "EXTERNEMITGLIEDSNUMMER") + members += m; + } + } + } + + public UserInfo[] get_members() { + return members; + } +} diff --git a/src/web/main.vala b/src/web/main.vala new file mode 100644 index 0000000..07dbb03 --- /dev/null +++ b/src/web/main.vala @@ -0,0 +1,35 @@ +/* Copyright 2013, Sebastian Reichel <sre@ring0.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +Database db; +public CSVMemberFile csvimport; +public PGP pgp; + +public static int main(string[] args) { + try { + db = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.Database", "/io/mainframe/shopsystem/database"); + pgp = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.PGP", "/io/mainframe/shopsystem/pgp"); + } catch(IOError e) { + error("IOError: %s\n", e.message); + } + + /* attach WebServer to MainLoop */ + new WebServer(); + + /* start MainLoop */ + new MainLoop().run(); + + return 0; +} diff --git a/src/template.vala b/src/web/template.vala index 8fe56d0..8fe56d0 100644 --- a/src/template.vala +++ b/src/web/template.vala diff --git a/src/web.vala b/src/web/web.vala index 7140c22..9dfb1ae 100644 --- a/src/web.vala +++ b/src/web/web.vala @@ -88,7 +88,8 @@ public class WebServer { try { var name = db.get_username(m); data += @"<tr><td>$m</td><td><a href=\"/users/$m\">$name</a></td></tr>"; - } catch(WebSessionError e) { + } catch(DatabaseError e) { + /* TODO: write error to log */ } } t.replace("DATA", data); @@ -184,11 +185,11 @@ public class WebServer { /* new & changed users */ string data1 = ""; foreach(var member in csvimport.get_members()) { - if(member.exists_in_db() && !member.equals_db()) { + if(db.user_exists(member.id) && db.user_equals(member)) { var dbmember = db.get_user_info(member.id); data1 += @"<tr class=\"error\"><td><i class=\"icon-minus-sign\"></i><td>$(dbmember.id)</td><td>$(dbmember.firstname)</td><td>$(dbmember.lastname)</td><td>$(dbmember.email)</td><td>$(dbmember.gender)</td><td>$(dbmember.street)</td><td>$(dbmember.postcode)</td><td>$(dbmember.city)</td><td>$(dbmember.pgp)</td></tr>"; } - if(!member.exists_in_db() || !member.equals_db()) { + if(!db.user_exists(member.id) || !db.user_equals(member)) { data1 += @"<tr class=\"success\"><td><i class=\"icon-plus-sign\"></td><td>$(member.id)</td><td>$(member.firstname)</td><td>$(member.lastname)</td><td>$(member.email)</td><td>$(member.gender)</td><td>$(member.street)</td><td>$(member.postcode)</td><td>$(member.city)</td><td>$(member.pgp)</td></tr>"; } } @@ -325,8 +326,8 @@ public class WebServer { t.menu_set_active("users"); /* years, in which something has been purchased by the user */ - var first = db.get_first_purchase(id); - var last = db.get_last_purchase(id); + var first = new DateTime.from_unix_local(db.get_first_purchase(id)); + var last = new DateTime.from_unix_local(db.get_last_purchase(id)); string years = ""; for(int i=first.get_year(); i <= last.get_year(); i++) { years += @"<li><a href=\"/users/$id/invoice/$i/$selectedmonth/$selectedday\">$i</a></li>"; @@ -659,7 +660,7 @@ public class WebServer { } } - +#if 0 void handler_stats(Soup.Server server, Soup.Message msg, string path, GLib.HashTable? query, Soup.ClientContext client) { try { var l = new WebSession(server, msg, path, query, client); @@ -749,6 +750,7 @@ public class WebServer { handler_404(server, msg, path, query, client); } } +#endif void handler_js(Soup.Server server, Soup.Message msg, string path, GLib.HashTable? query, Soup.ClientContext client) { try { @@ -837,12 +839,14 @@ public class WebServer { srv.add_handler("/products", handler_products); srv.add_handler("/products/new", handler_products_new); +#if 0 /* stats */ srv.add_handler("/stats", handler_stats); srv.add_handler("/stats/stock", handler_stats_stock); srv.add_handler("/stats/profit_per_day", handler_stats_profit_per_day); srv.add_handler("/stats/profit_per_weekday", handler_stats_profit_per_weekday); srv.add_handler("/stats/profit_per_product", handler_stats_profit_per_product); +#endif /* users */ srv.add_handler("/users", handler_users); diff --git a/src/websession.vala b/src/web/websession.vala index 5c562c6..5c562c6 100644 --- a/src/websession.vala +++ b/src/web/websession.vala |