From 0c55606145b6c5d9a303b19b3dba4996ec3ed3a9 Mon Sep 17 00:00:00 2001 From: Joel Klinghed Date: Thu, 25 Jun 2015 02:13:15 +0200 Subject: Split out common event code for future use --- src/event_utils.cc | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 src/event_utils.cc (limited to 'src/event_utils.cc') diff --git a/src/event_utils.cc b/src/event_utils.cc new file mode 100644 index 0000000..403d10f --- /dev/null +++ b/src/event_utils.cc @@ -0,0 +1,199 @@ +#include "common.hh" + +#include + +#include "config.hh" +#include "event.hh" +#include "event_utils.hh" +#include "fsutils.hh" +#include "sender_client.hh" +#include "sqlite3_db.hh" + +namespace stuff { + +namespace { + +class EventUtilsImpl : public EventUtils { +public: + EventUtilsImpl(const std::string& channel, + std::function error_cb, + Config* config, SenderClient* sender) + : channel_(channel), error_cb_(error_cb), cfg_(config), + sender_(sender) { + } + + std::unique_ptr create( + const std::string& name, time_t start) override { + if (!db_ && !open()) return nullptr; + return Event::create(db_, name, start); + } + + void created(Event* event) override { + if (!event) return; + auto next_event = Event::next(db_); + if (next_event->id() == event->id()) { + signal_event(next_event); + } + } + + std::vector> all() override { + if (!db_ && !open()) return std::vector>(); + return Event::all(db_); + } + + std::unique_ptr next() override { + if (!db_ && !open()) return nullptr; + return Event::next(db_); + } + + bool good() const override { + return db_.get() != nullptr; + } + + void cancel(Event* event, size_t index) override { + if (!event) return; + event->remove(); + if (index == 0) { + std::ostringstream ss; + ss << "Event canceled: " << event->name() << " @ " + << format_date(event->start()); + signal_channel(ss.str()); + } + } + + void updated(Event* event, int64_t was_first) override { + auto next_event = Event::next(db_); + if (next_event->id() != was_first || + next_event->id() == event->id()) { + signal_event(next_event); + } + } + + void going(Event* event, bool going, const std::string& user, + const std::string& owner) override { + auto next_event = Event::next(db_); + if (next_event->id() == event->id()) { + std::string extra; + if (user != owner) { + extra = " says " + owner; + } + if (going) { + signal_channel(user + " will be attending " + + event->name() + extra); + } else { + signal_channel(user + " will not be attending " + + event->name() + extra); + } + } + } + + const std::string& channel() const override { + return channel_; + } + +private: + void signal_event(const std::unique_ptr& event) { + std::ostringstream ss; + ss << event->name() << " @ " << format_date(event->start()) << std::endl; + if (!event->text().empty()) { + ss << event->text() << std::endl; + } + ss << std::endl; + ss << "Use /event going to join the event" << std::endl; + signal_channel(ss.str()); + } + + void signal_channel(const std::string& str) { + if (!sender_) return; + sender_->send(channel_, str); + } + + void error(const std::string& message) { + if (error_cb_) { + error_cb_(message); + } + } + + bool open() { + std::string tmp = channel_; + for (auto it = tmp.begin(); it != tmp.end(); ++it) { + if (!((*it >= 'a' && *it <= 'z') || + (*it >= 'A' && *it <= 'Z') || + (*it >= '0' && *it <= '9') || + *it == '-' || *it == '_' || *it == '.')) { + *it = '.'; + } + } + std::string path; + if (cfg_) path = cfg_->get("db_path", LOCALSTATEDIR); + if (path.empty()) path = "."; + if (!mkdir_p(path)) { + error("Unable to create database directory"); + return false; + } + auto db = SQLite3::open(path + "/" + tmp + ".db"); + if (!db || db->bad()) { + error("Unable to open database"); + return false; + } else if (!Event::setup(db.get())) { + error("Unable to setup database"); + return false; + } + db_ = std::move(db); + return true; + } + + std::string channel_; + std::function error_cb_; + std::shared_ptr db_; + Config* cfg_; + SenderClient* sender_; +}; + +} // namespace + +EventUtils::EventUtils() { +} + +EventUtils::~EventUtils() { +} + +std::unique_ptr EventUtils::create( + const std::string& channel, + std::function error_cb, + Config* config, + SenderClient* sender) { + std::unique_ptr utils( + new EventUtilsImpl(channel, error_cb, config, sender)); + return utils; +} + +const double EventUtils::ONE_DAY_IN_SEC = 24.0 * 60.0 * 60.0; +const double EventUtils::ONE_WEEK_IN_SEC = ONE_DAY_IN_SEC * 7.0; +// It's OK that we ignore leap years here +const double EventUtils::ONE_YEAR_IN_SEC = 365 * ONE_DAY_IN_SEC; + +std::string EventUtils::format_date(time_t date) { + time_t now = time(NULL); + struct tm _t; + struct tm* t = localtime_r(&date, &_t); + double diff = difftime(date, now); + char tmp[100]; + if (diff <= ONE_DAY_IN_SEC) { + // Same day, just show time + strftime(tmp, sizeof(tmp), "%H:%M", t); + } else if (diff <= ONE_WEEK_IN_SEC) { + // Inside a week, show day and time + strftime(tmp, sizeof(tmp), "%A %H:%M", t); + } else if (diff <= ONE_YEAR_IN_SEC / 2.0) { + // Inside a year, show date, day and time + strftime(tmp, sizeof(tmp), "%A %d/%m %H:%M", t); + } else { + strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M", t); + } + return tmp; +} + +} // namespace stuff + + -- cgit v1.2.3-70-g09d2