diff --git a/Makefile b/Makefile index e9bc04a..ac2fbe4 100755 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CC = g++ -o = dir.o data.o content.o log.o sessionmanager.o requestcontroller.o dircontainer.o session.o main.o done.o request.o misc.o templates.o httpsimpleparser.o db.o error.o config.o confparser.o ezc.o +o = dir.o data.o content.o log.o sessionmanager.o requestcontroller.o dircontainer.o session.o main.o done.o request.o misc.o templates.o httpsimpleparser.o db.o error.o db_itemcolumns.o config.o confparser.o ezc.o CFLAGS = -Wall -pedantic -g -I/usr/local/include -L/usr/local/lib name = cmslu.fcgi @@ -35,13 +35,13 @@ templates.o: core/templates.cpp core/templates.h core/../../ezc/src/ezc.h core httpsimpleparser.o: core/httpsimpleparser.cpp core/httpsimpleparser.h db.o: core/db.cpp core/db.h core/log.h core/item.h core/misc.h core/error.h core/dircontainer.h error.o: core/error.cpp core/error.h core/log.h +db_itemcolumns.o: core/db_itemcolumns.cpp core/db.h core/log.h core/item.h core/misc.h core/error.h core/dircontainer.h config.o: core/config.cpp core/config.h core/../confparser/confparser.h core/error.h core/log.h core/data.h core/misc.h core/item.h core/dir.h core/db.h core/dircontainer.h confparser.o: confparser/confparser.cpp confparser/confparser.h ezc.o: ../ezc/src/ezc.cpp ../ezc/src/ezc.h - clean: rm -f *.o rm -f $(name) diff --git a/core/content.cpp b/core/content.cpp index e38fd6d..f286d6e 100755 --- a/core/content.cpp +++ b/core/content.cpp @@ -175,12 +175,12 @@ void Content::PrepareUrlSubject(Item & item) { SetUrlSubjectFromSubject(item); - if( StandardFunction(item.url_subject) != Request::err404 ) + if( StandardFunction(item.url) != Request::err404 ) { // names of functions should not begin with an underscore '_' // and we can simply add one '_' at the beginning // and the name will be unique - item.url_subject.insert(item.url_subject.begin(), '_'); + item.url.insert(item.url.begin(), '_'); } } @@ -265,12 +265,12 @@ void Content::MakeGet() } if( request.get_table[get_index].empty() ) - // we do not have an empty url_subject + // we do not have an empty url // err404 at the end return; - // if we want to search by url_subject then request.get_table[get_index] should not be empty - item.url_subject = request.get_table[get_index++]; + // if we want to search by url then request.get_table[get_index] should not be empty + item.url = request.get_table[get_index++]; db.GetItems(request.item_table, item); if( request.item_table.empty() ) @@ -306,7 +306,7 @@ void Content::AppendCurDir(std::string & dir) for(a=0 ; aitem = request.item; - if( db.DelItem( request.item.id ) ) + if( db.DelItem( request.item ) ) { request.session->done = Done::deleted_item; request.session->done_status = Error::ok; @@ -402,7 +402,7 @@ void Content::MakeLogout() request.str = data.base_url + path; if( !request.item_table.empty() ) - request.str += request.item_table[0].url_subject; + request.str += request.item_table[0].url; request.session->done = Done::loggedout; request.session->done_timer = 2; diff --git a/core/db.cpp b/core/db.cpp index 07ec1e0..2d907d5 100755 --- a/core/db.cpp +++ b/core/db.cpp @@ -186,6 +186,7 @@ return res; } + void Db::ClearResult(PGresult * r) { if( r ) @@ -263,7 +264,7 @@ appendix[0] = 0; std::ostringstream query; // this Escape can be put at the beginning (performance) - query << "select id from core.item where url_subject='" << Escape(item.url_subject) << appendix << "' and parent_id='" << item.parent_id << "';"; + query << "select id from core.item where url='" << Escape(item.url) << appendix << "' and parent_id='" << item.parent_id << "';"; r = AssertQuery(query.str()); AssertResultStatus(r, PGRES_TUPLES_OK); @@ -274,7 +275,7 @@ appendix[0] = 0; } else { - item.url_subject += appendix; + item.url += appendix; is_that_url = false; } @@ -304,15 +305,15 @@ void Db::CheckAllUrlSubjectModifyItem(Item & item) try { std::ostringstream query; - query << "update core.item set url_subject="; + query << "update core.item set url="; - // url_subject + // url if( AddItemCreateUrlSubject(item) ) - query << '\'' << Escape(item.url_subject) << '\''; + query << '\'' << Escape(item.url) << '\''; else { query << '\'' << item.id << '\''; - item.url_subject.clear(); + item.url.clear(); } query << " where id='" << item.id << "';"; @@ -339,7 +340,7 @@ void Db::CheckAllUrlSubject() { AssertConnection(); std::ostringstream query, query2; - query << "select id, subject from core.item where url_subject is null or url_subject=''"; + query << "select item.id, subject from core.item left join core.content on item.content_id = content.id where url is null or url=''"; r = AssertQuery(query.str()); AssertResultStatus(r, PGRES_TUPLES_OK); @@ -350,7 +351,7 @@ void Db::CheckAllUrlSubject() for(int i = 0 ; i(item.type) << "', "; + query << '\'' << item.parent_id << "', "; + query << '\'' << item.content_id << "', "; - // url_subject url_without_id = AddItemCreateUrlSubject(item); if( url_without_id ) - { - query << '\'' << Escape(item.url_subject) << "', "; - } + query << '\'' << Escape(item.url) << "');"; else - { - query << "currval('core.item_id_seq')" << ", "; - } + query << "currval('core.item_id_seq')" << ");"; - query << '\'' << static_cast(item.type) << "', "; - query << '\'' << item.parent_id << "' "; - query << ");"; - r = AssertQuery(query.str()); AssertResultStatus(r, PGRES_COMMAND_OK); item.id = AssertCurrval("core.item_id_seq"); if( !url_without_id ) - ToString(item.url_subject, item.id); + ToString(item.url, item.id); } catch(const Error & e) @@ -439,7 +434,56 @@ return result; } -Error Db::EditItem(Item & item, bool with_subject) + +Error Db::AddItemIntoContent(Item & item) +{ + PGresult * r = 0; + Error result = Error::ok; + + try + { + AssertConnection(); + std::ostringstream query; + query << "insert into core.content (subject, content, content_type) values ("; + query << '\'' << Escape(item.subject) << "', "; + query << '\'' << Escape(item.content) << "', "; + query << '\'' << item.content_type << "');"; + + r = AssertQuery(query.str()); + AssertResultStatus(r, PGRES_COMMAND_OK); + + item.content_id = AssertCurrval("core.content_id_seq"); + } + catch(const Error & e) + { + result = e; + } + + ClearResult(r); + + +return result; +} + + + + +Error Db::AddItem(Item & item) +{ + Error result = AddItemIntoContent(item); + + if( result == Error::ok ) + result = AddItemIntoItem(item); + +return result; +} + + + + + + +Error Db::EditItemInItem(Item & item, bool with_subject) { PGresult * r = 0; Error result = Error::ok; @@ -449,41 +493,35 @@ Error Db::EditItem(Item & item, bool with_subject) { AssertConnection(); std::ostringstream query; - query << "update core.item set ("; + query << "update core.item set (user_id, group_id, privileges, type, parent_id,"; if( with_subject ) - query << "subject, url_subject, "; + query << " url"; - query << "content, type, parent_id) = ("; + query << ") = ("; + query << '\'' << item.user_id << "', "; + query << '\'' << item.group_id << "', "; + query << '\'' << item.privileges << "', "; + query << '\'' << static_cast(item.type) << "', "; + query << '\'' << item.parent_id << "' "; if( with_subject ) { - query << '\'' << Escape(item.subject) << "', "; - - // url_subject url_without_id = AddItemCreateUrlSubject(item); if( url_without_id ) - { - query << '\'' << Escape(item.url_subject) << "', "; - } + query << ", '" << Escape(item.url) << "'"; else - { - query << '\'' << item.id << "', "; - } + query << ", '" << item.id << "'"; } - query << '\'' << Escape(item.content) << "', "; - - query << '\'' << static_cast(item.type) << "', "; - query << '\'' << item.parent_id << "' "; query << ") where id='" << item.id << "';"; r = AssertQuery(query.str()); AssertResultStatus(r, PGRES_COMMAND_OK); if( with_subject && !url_without_id ) - ToString(item.url_subject, item.id); + ToString(item.url, item.id); } catch(const Error & e) { @@ -497,16 +535,62 @@ return result; +Error Db::EditItemInContent(Item & item) +{ + PGresult * r = 0; + Error result = Error::ok; + + try + { + AssertConnection(); + std::ostringstream query; + query << "update core.content set (subject, content, content_type) = ("; + + query << '\'' << Escape(item.subject) << "', "; + query << '\'' << Escape(item.content) << "', "; + query << '\'' << item.content_type << "' "; + + query << ") where id='" << item.content_id << "';"; + + r = AssertQuery(query.str()); + AssertResultStatus(r, PGRES_COMMAND_OK); + } + catch(const Error & e) + { + result = e; + } + + ClearResult(r); + +return result; +} + + + + +Error Db::EditItem(Item & item, bool with_subject) +{ + Error result = EditItemInContent(item); + + if( result == Error::ok ) + result = EditItemInItem(item, with_subject); + +return result; +} + + + + PGresult * Db::GetItemsQuery(Item & item_ref) { std::ostringstream query; - query << "select * from core.item where type!='0' and parent_id='" << item_ref.parent_id << "'"; + query << "select * from core.item left join core.content on item.content_id = content.id where type!='0' and parent_id='" << item_ref.parent_id << "'"; if( item_ref.id != -1 ) - query << " and id='" << item_ref.id << "'"; + query << " and item.id='" << item_ref.id << "'"; - if( !item_ref.url_subject.empty() ) - query << " and url_subject='" << Escape(item_ref.url_subject) << "'"; + if( !item_ref.url.empty() ) + query << " and url='" << Escape(item_ref.url) << "'"; query << ';'; @@ -557,7 +641,7 @@ void Db::GetItem(std::vector & item_table, long id) AssertConnection(); std::ostringstream query; - query << "select * from core.item where type='1' and id='" << id << "';"; + query << "select * from core.item left join core.content on item.content_id = content.id where type='1' and item.id='" << id << "';"; r = AssertQuery( query.str() ); AssertResultStatus(r, PGRES_TUPLES_OK); @@ -585,9 +669,11 @@ void Db::GetItem(std::vector & item_table, long id) } -bool Db::DelItem(long id) + + +bool Db::DelItemDelItem(const Item & item) { - long rows = 0; + long rows = 0; PGresult * r = 0; try @@ -595,7 +681,7 @@ bool Db::DelItem(long id) AssertConnection(); std::ostringstream query; - query << "delete from core.item where type='1' and id='" << id << "';"; + query << "delete from core.item where id='" << item.id << "';"; r = AssertQuery( query.str() ); AssertResultStatus(r, PGRES_COMMAND_OK); @@ -607,6 +693,9 @@ bool Db::DelItem(long id) if( rows > 1 ) log << log1 << "Db: more than one item were deleted" << logend; + else + if( rows == 0 ) + log << log1 << "Db: no item has been deleted" << logend; } } catch(const Error &) @@ -619,6 +708,93 @@ return rows != 0; } + + +void Db::DelItemDelContent(const Item & item) +{ + PGresult * r = 0; + + try + { + AssertConnection(); + + std::ostringstream query; + query << "delete from core.content where id='" << item.content_id << "';"; + + r = AssertQuery( query.str() ); + AssertResultStatus(r, PGRES_COMMAND_OK); + + const char * crows = PQcmdTuples(r); + if( crows ) + { + long rows = atol(crows); + + if( rows > 1 ) + log << log1 << "Db: more than one content were deleted" << logend; + else + if( rows == 0 ) + log << log1 << "Db: no content has been deleted" << logend; + + } + } + catch(const Error &) + { + } + + ClearResult(r); +} + + + + +Error Db::DelItemCountContents(const Item & item, long & contents) +{ + Error result = Error::ok; + PGresult * r = 0; + + try + { + AssertConnection(); + + std::ostringstream query; + query << "select count('id') from core.item where content_id='" << item.content_id << "';"; + + r = AssertQuery( query.str() ); + AssertResultStatus(r, PGRES_TUPLES_OK); + + contents = atol( AssertValue(r, 0, 0) ); + + log << log1 << "counters: " << contents << logend; // !! + } + catch(const Error & e) + { + result = e; + } + + ClearResult(r); + +return result; +} + + + +bool Db::DelItem(const Item & item) +{ +long contents; + + Error result = DelItemCountContents(item, contents); + + if( result == Error::ok && contents == 1 ) + DelItemDelContent(item); + +return DelItemDelItem(item); +} + + + + + + void Db::GetDirs(DirContainer & dir_table) { PGresult * r = 0; @@ -628,7 +804,7 @@ void Db::GetDirs(DirContainer & dir_table) AssertConnection(); std::ostringstream query; - query << "select * from core.item where type='0';"; + query << "select * from core.item left join core.content on item.content_id = content.id where type='0';"; r = AssertQuery( query.str() ); AssertResultStatus(r, PGRES_TUPLES_OK); diff --git a/core/db.h b/core/db.h index 6d6aab5..aa9b9a1 100755 --- a/core/db.h +++ b/core/db.h @@ -29,84 +29,64 @@ class Db { +public: + + Db(); + ~Db(); + + void Init(const std::string & database, const std::string & user, const std::string & pass); + bool CheckUser(std::string & login, std::string & password, long & user_id); + Error AddItem(Item & item); + Error EditItem(Item & item, bool with_subject = true); + void CheckAllUrlSubject(); + void GetItems(std::vector & item_table, Item & item_ref); + void GetItem(std::vector & item_table, long id); + bool DelItem(const Item & item); + void GetDirs(DirContainer & dir_table); + + + protected: PGconn * pg_conn; - std::string db_database, db_user, db_pass; - -public: - -Db(); -~Db(); - -void Init(const std::string & database, const std::string & user, const std::string & pass); -void Connect(); - -void Close(); -void AssertConnection(); -std::string Escape(const std::string & s); -std::string Escape(const char * s); - -PGresult * AssertQuery(const std::string & q); -void AssertResultStatus(PGresult * r, ExecStatusType t); -static int AssertColumn(PGresult * r, const char * column_name); -static const char * AssertValue(PGresult * r, int row, int col); - -void ClearResult(PGresult * r); -bool CheckUser(std::string & login, std::string & password, long & user_id); - -long AssertCurrval(const char * table); - - -bool AddItemCreateUrlSubject(Item & item); -Error AddItem(Item & item); -Error EditItem(Item & item, bool with_subject = true); - -void CheckAllUrlSubjectModifyItem(Item & item); -void CheckAllUrlSubject(); - -PGresult * GetItemsQuery(Item & item_ref); -void GetItems(std::vector & item_table, Item & item_ref); -void GetItem(std::vector & item_table, long id); - -bool DelItem(long id); - -void GetDirs(DirContainer & dir_table); - - - -struct ItemColumns -{ - int id, subject, content, url_subject, type, parent_id, default_item; - - void SetColumns(PGresult * r) - { - id = Db::AssertColumn(r, "id"); - subject = Db::AssertColumn(r, "subject"); - content = Db::AssertColumn(r, "content"); - url_subject = Db::AssertColumn(r, "url_subject"); - type = Db::AssertColumn(r, "type"); - parent_id = Db::AssertColumn(r, "parent_id"); - default_item = Db::AssertColumn(r, "default_item"); - } - - - void SetItem(PGresult * r, long row, Item & item) - { - item.id = atol( Db::AssertValue(r, row, id) ); - item.subject = Db::AssertValue(r, row, subject); - item.content = Db::AssertValue(r, row, content); - item.url_subject = Db::AssertValue(r, row, url_subject); - item.type = static_cast( atoi( Db::AssertValue(r, row, type) ) ); - item.parent_id = atol( Db::AssertValue(r, row, parent_id) ); - item.default_item = atol( Db::AssertValue(r, row, default_item) ); - } + void Connect(); + void Close(); + void AssertConnection(); + std::string Escape(const std::string & s); + std::string Escape(const char * s); + PGresult * AssertQuery(const std::string & q); + void AssertResultStatus(PGresult * r, ExecStatusType t); + static int AssertColumn(PGresult * r, const char * column_name); + static const char * AssertValue(PGresult * r, int row, int col); + void ClearResult(PGresult * r); + long AssertCurrval(const char * table); + bool AddItemCreateUrlSubject(Item & item); - -}; + Error AddItemIntoContent(Item & item); + Error AddItemIntoItem(Item & item); + + Error EditItemInItem(Item & item, bool with_subject); + Error EditItemInContent(Item & item); + + void CheckAllUrlSubjectModifyItem(Item & item); + + PGresult * GetItemsQuery(Item & item_ref); + + bool DelItemDelItem(const Item & item); + void DelItemDelContent(const Item & item); + Error DelItemCountContents(const Item & item, long & contents); + + + struct ItemColumns + { + int id, user_id, group_id, privileges, url, type, parent_id, content_id, default_item, subject, content, content_type; + + void SetColumns(PGresult * r); + void SetItem(PGresult * r, long row, Item & item); + }; }; // class Db diff --git a/core/db_itemcolumns.cpp b/core/db_itemcolumns.cpp new file mode 100755 index 0000000..7ce89ec --- /dev/null +++ b/core/db_itemcolumns.cpp @@ -0,0 +1,46 @@ +#include "db.h" + + + +void Db::ItemColumns::SetColumns(PGresult * r) +{ + // PQfnumber returns -1 if there is no such a column + id = PQfnumber(r, "id"); // !! why item.id doesn't work? + user_id = PQfnumber(r, "user_id"); + group_id = PQfnumber(r, "group_id"); + privileges = PQfnumber(r, "privileges"); + url = PQfnumber(r, "url"); + type = PQfnumber(r, "type"); + parent_id = PQfnumber(r, "parent_id"); + content_id = PQfnumber(r, "content_id"); + default_item = PQfnumber(r, "default_item"); + subject = PQfnumber(r, "subject"); + content = PQfnumber(r, "content"); + content_type = PQfnumber(r, "content_type"); +} + + + +void Db::ItemColumns::SetItem(PGresult * r, long row, Item & item) +{ + if( id != -1 ) item.id = atol( Db::AssertValue(r, row, id) ); + if( user_id != -1 ) item.user_id = atol( Db::AssertValue(r, row, user_id) ); + if( group_id != -1 ) item.group_id = atol( Db::AssertValue(r, row, group_id) ); + if( privileges != -1 ) item.privileges = atoi( Db::AssertValue(r, row, privileges) ); + if( url != -1 ) item.url = Db::AssertValue(r, row, url); + if( type != -1 ) item.type = static_cast( atoi( Db::AssertValue(r, row, type) ) ); + if( parent_id != -1 ) item.parent_id = atol( Db::AssertValue(r, row, parent_id) ); + if( content_id != -1 ) item.content_id = atol( Db::AssertValue(r, row, content_id) ); + if( default_item != -1 ) item.default_item = atol( Db::AssertValue(r, row, default_item) ); + if( subject != -1 ) item.subject = Db::AssertValue(r, row, subject); + if( content != -1 ) item.content = Db::AssertValue(r, row, content); + if( content_type != -1 ) item.content_type = atoi( Db::AssertValue(r, row, content_type) ); +} + + + + + + + + diff --git a/core/dir.cpp b/core/dir.cpp index 4fe5c6f..efd9df8 100755 --- a/core/dir.cpp +++ b/core/dir.cpp @@ -35,7 +35,7 @@ bool Dir::GetDir(const std::string & name, long parent, Item ** item) DirContainer::ParentIterator i = dir_table.FindFirstParent(parent); for( ; i!=dir_table.ParentEnd() ; i = dir_table.NextParent(i) ) - if( i->second->url_subject == name ) + if( i->second->url == name ) { *item = &(*i->second); return true; @@ -164,7 +164,7 @@ DirContainer::Iterator i; id = i->parent_id; path.insert(path.begin(), '/'); - path.insert(0, i->url_subject); + path.insert(0, i->url); } } diff --git a/core/item.h b/core/item.h index 508b146..fbfd295 100755 --- a/core/item.h +++ b/core/item.h @@ -19,9 +19,19 @@ struct Item { long id; + +long user_id; +long group_id; +int privileges; + + std::string subject; std::string content; -std::string url_subject; +std::string url; + + +int content_type; + enum Type { @@ -41,6 +51,9 @@ long parent_id; long default_item; +// used by the database +long content_id; + Item() { @@ -52,13 +65,22 @@ Item() void Clear() { id = -1; + + user_id = -1; + group_id = -1; + privileges = 0; + subject.clear(); content.clear(); - url_subject.clear(); + url.clear(); + + content_type = 0; type = none; parent_id = -1; default_item = -1; + + content_id = -1; } diff --git a/core/misc.cpp b/core/misc.cpp index 0798a0b..2c71ec5 100755 --- a/core/misc.cpp +++ b/core/misc.cpp @@ -35,7 +35,7 @@ void SetUrlSubjectFromSubject(Item & item) { std::string::iterator i; - item.url_subject.clear(); + item.url.clear(); for(i = item.subject.begin(); i!=item.subject.end() ; ++i) { @@ -47,18 +47,18 @@ std::string::iterator i; (c == '(' || c == ')' || c == '.' || c == ',' || c == '_' ) ) { - item.url_subject += c; + item.url += c; } else - item.url_subject += '_'; + item.url += '_'; } - if( item.url_subject.empty() ) - item.url_subject = "bez_nazwy"; + if( item.url.empty() ) + item.url = "bez_nazwy"; // !! wrzucic do pliku konfiguracyjnego else - if( item.url_subject[0] >= '0' && item.url_subject[0] <= '9' ) - // url_subject must begin with a letter - item.url_subject.insert(item.url_subject.begin(), '_'); + if( item.url[0] >= '0' && item.url[0] <= '9' ) + // url must begin with a letter + item.url.insert(item.url.begin(), '_'); } diff --git a/core/request.h b/core/request.h index 649f7f0..ae53c17 100755 --- a/core/request.h +++ b/core/request.h @@ -59,7 +59,7 @@ struct Request // what to do enum Result { err_internal, err404, show_dir, show_item, show_item_by_id, add_item, edit_item, del_item, del_item_confirm, confirm, redirect, logout } result; // zamienic na to_do - //Item item; // bedziemy uzywac tego, item_id i item_url_subject wywalic + diff --git a/core/templates.cpp b/core/templates.cpp index 5b1e7ee..b67b34e 100755 --- a/core/templates.cpp +++ b/core/templates.cpp @@ -148,9 +148,9 @@ void item_content(Info & i) } -void item_url_subject(Info & i) +void item_url_subject(Info & i) // !! zmienic nazwe { - i.out << request.item.url_subject; + i.out << request.item.url; } @@ -190,9 +190,9 @@ i.out << request.session->item.content; } -void old_item_url_subject(Info & i) +void old_item_url_subject(Info & i) // zmienic nazwe !! { - i.out << request.session->item.url_subject; + i.out << request.session->item.url; } @@ -220,7 +220,7 @@ std::vector::size_type a; for(a=0 ; a::size_type a; @@ -351,10 +345,16 @@ void current_dir_part_url(Info & i) for(a = 0 ; a <= current_dir_index && a < request.cur_dir_table.size() ; ++a) { - i.out << request.cur_dir_table[a].url_subject << '/'; + i.out << request.cur_dir_table[a].url << '/'; } } +void current_dir_part_url(Info & i) +{ + if( current_dir_index < request.cur_dir_table.size() ) + i.out << request.cur_dir_table[current_dir_index].url; +} + void edit_item(Info & i) @@ -467,7 +467,7 @@ void Templates::CreateFunctions() functions.Insert("incorrect_dir", incorrect_dir); functions.Insert("fcurrent_dir", fcurrent_dir); - functions.Insert("current_dir_part_name", current_dir_part_name); + functions.Insert("current_dir_part_link", current_dir_part_link); functions.Insert("current_dir_part_url", current_dir_part_url); functions.Insert("added_item", added_item);