diff --git a/sconesite/Makefile.am b/sconesite/Makefile.am index 370c345..99b9866 100644 --- a/sconesite/Makefile.am +++ b/sconesite/Makefile.am @@ -16,6 +16,7 @@ Heading.cpp \ Profile.cpp \ RenderMarkup.cpp \ Template.cpp \ +TemplateManager.cpp \ XMLDoc.cpp sconesiteincludedir = $(includedir)/sconesite @@ -30,6 +31,7 @@ Heading.h \ Profile.h \ RenderMarkup.h \ Template.h \ +TemplateManager.h \ XMLDoc.h sconesite_la_LDFLAGS = -module -avoid-version diff --git a/sconesite/Profile.cpp b/sconesite/Profile.cpp index a956463..fb1be55 100644 --- a/sconesite/Profile.cpp +++ b/sconesite/Profile.cpp @@ -52,24 +52,20 @@ Profile::Profile( SconesiteModule& module, const std::string& name, http::Host* host, - const std::string& dbtype + scx::Database* db ) : m_module(module), m_name(name), m_host(new http::Host::Ref(host)), - m_db(0) + m_db(new scx::Database::Ref(db)), + m_use_default_templates(true) { m_parent = &m_module; - // Open article database - scx::ScriptMap::Ref args(new scx::ScriptMap()); - args.object()->give("profile",scx::ScriptString::new_ref(name)); - m_db = scx::Database::open(dbtype,&args); - - if (!m_db) throw std::exception(); - + check_database(); configure_docroot("default"); configure_docroot("secure"); - + m_templates.add(get_path() + TPLDIR); + refresh(); } @@ -80,10 +76,6 @@ Profile::~Profile() it_a != m_articles.end(); ++it_a) { delete it_a->second; } - for (TemplateMap::iterator it_t = m_templates.begin(); - it_t != m_templates.end(); ++it_t) { - delete it_t->second; - } delete m_db; delete m_host; @@ -92,36 +84,7 @@ Profile::~Profile() //========================================================================= void Profile::refresh() { - // Add new templates - scx::FileDir dir(get_path() + TPLDIR); - while (dir.next()) { - std::string file = dir.name(); - if (file != "." && file != "..") { - std::string::size_type idot = file.find_first_of("."); - if (idot != std::string::npos) { - std::string name = file.substr(0,idot); - std::string extn = file.substr(idot+1,std::string::npos); - if (extn == "xml" && !lookup_template(name)) { - Template* tpl = new Template(*this,name,dir.root()); - m_templates[name] = new Template::Ref(tpl); - LOG("Adding template '" + name + "'"); - } - } - } - } - - // Remove deleted templates - for (TemplateMap::iterator it_t = m_templates.begin(); - it_t != m_templates.end(); - ++it_t) { - Template::Ref* tpl_ref = it_t->second; - Template* tpl = tpl_ref->object(); - if (!scx::FileStat(tpl->get_filepath()).is_file()) { - LOG("Removing template '" + tpl->get_name() + "'"); - it_t = m_templates.erase(it_t); - delete tpl_ref; - } - } + m_templates.refresh(); // Calculate purge time for cached articles scx::Date purge_time; @@ -532,11 +495,10 @@ bool Profile::rename_article(int id, //========================================================================= Template* Profile::lookup_template(const std::string& name) { - TemplateMap::iterator it = m_templates.find(name); - if (it != m_templates.end()) { - return it->second->object(); - } - return 0; + Template* t = m_templates.lookup(name); + if (t) return t; + if (m_use_default_templates) t = m_module.lookup_template(name); + return t; } //========================================================================= @@ -559,7 +521,9 @@ scx::ScriptRef* Profile::script_op(const scx::ScriptAuth& auth, "lookup" == name || "create_article" == name || "remove_article" == name || - "rename_article" == name) { + "rename_article" == name || + "add_templates" == name || + "set_use_default_templates" == name) { return new scx::ScriptMethodRef(ref,name); } @@ -570,6 +534,9 @@ scx::ScriptRef* Profile::script_op(const scx::ScriptAuth& auth, if ("path" == name) return scx::ScriptString::new_ref(get_path().path()); + if ("db" == name) + return m_db->ref_copy(); + if ("article_cache" == name) { scx::ScriptList::Ref* list = new scx::ScriptList::Ref(new scx::ScriptList()); @@ -588,6 +555,9 @@ scx::ScriptRef* Profile::script_op(const scx::ScriptAuth& auth, } return list; } + + if ("use_default_templates" == name) + return scx::ScriptInt::new_ref(m_use_default_templates); } return scx::ScriptObject::script_op(auth,ref,op,right); @@ -693,6 +663,33 @@ scx::ScriptRef* Profile::script_method(const scx::ScriptAuth& auth, return 0; } + if ("add_templates" == name) { + if (!auth.admin()) return scx::ScriptError::new_ref("Not permitted"); + + const scx::ScriptString* a_path = + scx::get_method_arg(args,0,"path"); + if (!a_path) { + return scx::ScriptError::new_ref("No path specified"); + } + m_templates.add(a_path->get_string()); + + return 0; + } + + if ("set_use_default_templates" == name) { + if (!auth.admin()) return scx::ScriptError::new_ref("Not permitted"); + + const scx::ScriptInt* a_value = + scx::get_method_arg(args,0,"value"); + if (!a_value) { + return scx::ScriptError::new_ref("No value specified"); + } + + m_use_default_templates = (a_value->get_int() != 0); + + return 0; + } + return scx::ScriptObject::script_method(auth,ref,name,args); } @@ -770,4 +767,26 @@ void Profile::configure_docroot(const std::string& docroot) } } +//============================================================================= +void Profile::check_database() +{ + if (!m_db) throw std::exception(); + + // Create article table if not present + if (!m_db->object()->simple_query( + "CREATE TABLE IF NOT EXISTS article ( " + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "parent INTEGER, " + "path VARCHAR(128) )")) { + LOG("Failed to create article table"); + } + + // Create root article if not present + if (m_db->object()->simple_query_num( + "SELECT COUNT(*) FROM article WHERE id = 1") != 1) { + m_db->object()->simple_query( + "INSERT INTO article (id,parent,path) VALUES (1,0,\"\")"); + } +} + }; diff --git a/sconesite/Profile.h b/sconesite/Profile.h index 97991f9..2be19d4 100644 --- a/sconesite/Profile.h +++ b/sconesite/Profile.h @@ -23,7 +23,7 @@ Free Software Foundation, Inc., #define sconesiteProfile_h #include -#include +#include #include #include #include @@ -44,7 +44,7 @@ class Profile : public scx::ScriptObject { Profile(SconesiteModule& module, const std::string& name, http::Host* host, - const std::string& dbtype); + scx::Database* db); ~Profile(); @@ -117,6 +117,7 @@ class Profile : public scx::ScriptObject { const std::string& link, const std::string& type=""); + void check_database(); void configure_docroot(const std::string& docroot); private: @@ -139,10 +140,9 @@ class Profile : public scx::ScriptObject { typedef HASH_TYPE ArticleLinkMap; ArticleLinkMap m_article_links; - // Templates - typedef HASH_TYPE TemplateMap; - TemplateMap m_templates; - + TemplateManager m_templates; + bool m_use_default_templates; + scx::Time m_purge_threshold; }; diff --git a/sconesite/SconesiteModule.cpp b/sconesite/SconesiteModule.cpp index 97e0e66..f29bc06 100644 --- a/sconesite/SconesiteModule.cpp +++ b/sconesite/SconesiteModule.cpp @@ -169,6 +169,7 @@ void SconesiteModule::provide(const std::string& type, //========================================================================= void SconesiteModule::refresh() { + m_templates.refresh(); for (ProfileMap::iterator it = m_profiles.begin(); it != m_profiles.end(); ++it) { @@ -184,10 +185,15 @@ Profile* SconesiteModule::lookup_profile(const std::string& profile) if (it != m_profiles.end()) { return it->second->object(); } - return 0; } +//============================================================================= +Template* SconesiteModule::lookup_template(const std::string& name) +{ + return m_templates.lookup(name); +} + //============================================================================= scx::ScriptRef* SconesiteModule::script_op(const scx::ScriptAuth& auth, const scx::ScriptRef& ref, @@ -198,7 +204,8 @@ scx::ScriptRef* SconesiteModule::script_op(const scx::ScriptAuth& auth, const std::string name = right->object()->get_string(); // Methods - if ("add" == name) { + if ("add" == name || + "add_templates" == name) { return new scx::ScriptMethodRef(ref,name); } @@ -254,17 +261,31 @@ scx::ScriptRef* SconesiteModule::script_method(const scx::ScriptAuth& auth, if (it != m_profiles.end()) return scx::ScriptError::new_ref("Profile already exists"); - std::string s_dbtype = "MySQL"; - const scx::ScriptString* a_dbtype = - scx::get_method_arg(args,1,"dbtype"); - if (a_dbtype) s_dbtype = a_dbtype->get_string(); + scx::Database* a_db = + const_cast( + scx::get_method_arg(args,1,"db")); + if (!a_db) + return scx::ScriptError::new_ref("No database specified"); - LOG("Adding profile '" + s_profile + "' dbtype '" + s_dbtype + "'"); - Profile* profile = new Profile(*this,s_profile,host,s_dbtype); + LOG("Adding profile '" + s_profile); + Profile* profile = new Profile(*this,s_profile,host,a_db); m_profiles[s_profile] = new Profile::Ref(profile); return new Profile::Ref(profile); } + + if ("add_templates" == name) { + if (!auth.admin()) return scx::ScriptError::new_ref("Not permitted"); + + const scx::ScriptString* a_path = + scx::get_method_arg(args,0,"path"); + if (!a_path) { + return scx::ScriptError::new_ref("No path specified"); + } + m_templates.add(a_path->get_string()); + + return 0; + } return scx::Module::script_method(auth,ref,name,args); } diff --git a/sconesite/SconesiteModule.h b/sconesite/SconesiteModule.h index 8bba627..1c5165b 100644 --- a/sconesite/SconesiteModule.h +++ b/sconesite/SconesiteModule.h @@ -46,6 +46,9 @@ class SconesiteModule : public scx::Module, void refresh(); Profile* lookup_profile(const std::string& name); + // Lookup a template in the standard template stores + Template* lookup_template(const std::string& name); + // Module methods virtual scx::ScriptRef* script_op(const scx::ScriptAuth& auth, const scx::ScriptRef& ref, @@ -76,6 +79,8 @@ class SconesiteModule : public scx::Module, typedef HASH_TYPE ProfileMap; ProfileMap m_profiles; + TemplateManager m_templates; + scx::JobID m_job; }; diff --git a/sconesite/SconesiteStream.cpp b/sconesite/SconesiteStream.cpp index 70904cc..7cae8b1 100644 --- a/sconesite/SconesiteStream.cpp +++ b/sconesite/SconesiteStream.cpp @@ -303,9 +303,9 @@ scx::Condition SconesiteStream::send_response() } // Find the template to use - Template* tpl = m_profile.lookup_template("default"); + Template* tpl = m_profile.lookup_template("start"); if (!tpl) { - log("No default template"); + log("start template not found"); resp.set_status(http::Status::InternalServerError); return scx::Close; } diff --git a/sconesite/Template.cpp b/sconesite/Template.cpp index d73612c..92da0fa 100644 --- a/sconesite/Template.cpp +++ b/sconesite/Template.cpp @@ -32,13 +32,11 @@ namespace scs { //========================================================================= Template::Template( - Profile& profile, const std::string& name, const scx::FilePath& path -) : XMLDoc(name,path,name + ".xml"), - m_profile(profile) +) : XMLDoc(name,path,name + ".xml") { - m_parent = &profile; + } //========================================================================= diff --git a/sconesite/Template.h b/sconesite/Template.h index 77bd3be..42bed41 100644 --- a/sconesite/Template.h +++ b/sconesite/Template.h @@ -34,20 +34,13 @@ class Template : public XMLDoc { public: - Template(Profile& profile, - const std::string& name, + Template(const std::string& name, const scx::FilePath& path); ~Template(); typedef scx::ScriptRefTo