From 951d0e8653f979b5ca5e14362f833f5e6e7a3dff Mon Sep 17 00:00:00 2001 From: Tomasz Sowa Date: Fri, 6 Feb 2009 13:12:03 +0000 Subject: [PATCH] changed: DirContainer - uses std::list instead of std::vector as the main container we do not have to rebuild indexes after deleting some items added: DirContainer::DelById(long id) changed: Dirs::CheckRootDir() addes the root dir if there is no one added: Dirs::DeleteDir(long id) - deletes specified directory (and its contents) (from the cache and the database) added: Db::DelDirById(long id) - deletes a dir from the database and its first children added: standard function rm can delete directories git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@487 e52654a7-88a9-db11-a3e9-0013d4bc506e --- content/content.cpp | 11 +++- content/content.h | 4 ++ content/rm.cpp | 82 ++++++++++++++++++++++++--- core/db.cpp | 40 +++++++++++++ core/db.h | 2 + core/dircontainer.cpp | 123 +++++++++++++++++++++++----------------- core/dircontainer.h | 17 +++--- core/dirs.cpp | 63 ++++++++++++++------ core/dirs.h | 27 ++++----- core/done.h | 1 + core/error.h | 2 +- core/functionparser.cpp | 1 + core/session.cpp | 9 ++- core/session.h | 3 + templates/dir.cpp | 5 ++ templates/done.cpp | 5 ++ templates/templates.cpp | 6 +- templates/templates.h | 4 ++ 18 files changed, 303 insertions(+), 102 deletions(-) diff --git a/content/content.cpp b/content/content.cpp index 94f1963..f3deeb3 100755 --- a/content/content.cpp +++ b/content/content.cpp @@ -65,6 +65,8 @@ void Content::SetDefaultFunction() } else { + request.session->IncrementTimersIfExist(); + log << log3 << "Content: Default item: id: " << default_item << logend; RedirectTo(default_item); } @@ -169,7 +171,7 @@ void Content::Make() { if( request.dir_table.empty() ) { - log << log1 << "Content: there is no a root dir" << logend; + log << log1 << "Content: there is no a root dir (dir_table is empty)" << logend; return; } @@ -194,6 +196,13 @@ void Content::Make() if( request.result == Request::redirect ) return; + + if( request.dir_table.empty() ) + { + log << log1 << "Content: there is no a root dir (dir_table is empty -- after calling some standard functions)" << logend; + return; + } + templates.Generate(); diff --git a/content/content.h b/content/content.h index 704f0d4..c1fe022 100755 --- a/content/content.h +++ b/content/content.h @@ -48,7 +48,11 @@ class Content void FunLs(); void FunEmacs(); void FunPriv(); + + void FunRmDirRecursive(); + void FunRmDir(); void FunRm(); + void FunNode(); void FunMkdir(); void FunDefault(); diff --git a/content/rm.cpp b/content/rm.cpp index 1216506..edc27f7 100755 --- a/content/rm.cpp +++ b/content/rm.cpp @@ -10,21 +10,88 @@ #include "content.h" +void Content::FunRmDirRecursive() +{ + data.dirs.MakePath(request.dir_table.back()->id, request.session->dir_old); + + // this method deletes recursively all directories + data.dirs.DeleteDir(request.dir_table.back()->id); + + request.dir_table.erase(--request.dir_table.end()); + + if( request.dir_table.empty() ) + { + // we have deleted the root directory + + data.dirs.CheckRootDir(); + + Item * proot = data.dirs.GetRootDir(); + + if( proot ) + request.dir_table.push_back(proot); + else + // there is no a root dir + // CheckRootDir() didn't add the root dir (probably problem with the database) + // make sure that Content::Make() will check that the dir_table is empty and returns + return; + } + + + request.session->done = Done::deleted_dir; + request.session->done_status = Error::ok; + request.session->done_timer = 2; + + // redirect to the last valid directory + RedirectTo(**(--request.dir_table.end())); +} +void Content::FunRmDir() +{ + if( request.dir_table.size() == 1 ) + { + // rm for the root dir + // only the superuser can do it + if( !request.session->puser || !request.session->puser->super_user ) + { + request.status = Error::permision_denied; + return; + } + } + else + { + Item * last_but_one_dir = *(--(--request.dir_table.end())); + + if( !request.HasWriteAccess(*last_but_one_dir) ) + { + request.status = Error::permision_denied; + return; + } + } + + + if( request.param_table.empty() ) + request.status = Error::permision_denied; + else + if( request.IsParam("confirm") ) + return; + else + if( request.IsParam("r") ) + FunRmDirRecursive(); + else + request.status = Error::unknown_param; +} void Content::FunRm() { - // !! narazie usuwanie tylko dla plikow - if( !request.is_item ) { - request.status = Error::permision_denied; + FunRmDir(); return; } - if( !request.HasWriteAccess(*request.dir_table.back()) || !request.HasWriteAccess(request.item) ) + if( !request.HasWriteAccess(*request.dir_table.back()) ) { request.status = Error::permision_denied; return; @@ -49,16 +116,15 @@ void Content::FunRm() } request.session->done = Done::deleted_item; - request.result = Request::redirect; - + RedirectTo(*request.dir_table.back()); - request.session->done_timer = 2; } else { if( !request.IsParam("confirm") ) - request.result = Request::err404; + //request.result = Request::err404; + request.status = Error::unknown_param; } } diff --git a/core/db.cpp b/core/db.cpp index da42f25..0412914 100755 --- a/core/db.cpp +++ b/core/db.cpp @@ -986,6 +986,46 @@ return result; +Error Db::DelDirById(long id) +{ + Error result = Error::ok; + PGresult * r = 0; + const char * crows; + + try + { + AssertConnection(); + std::ostringstream query, query2; + + query << "delete from core.content where content.id in (select content_id from core.item where parent_id='" << id << "');"; + r = AssertQuery( query.str() ); + AssertResultStatus(r, PGRES_COMMAND_OK); + + crows = PQcmdTuples(r); + if( crows ) + log << log2 << "Db: deleted " << atol(crows) << " rows from core.content" << logend; + + query2 << "delete from core.item where id='" << id << "' or parent_id='" << id << "';"; + r = AssertQuery( query2.str() ); + AssertResultStatus(r, PGRES_COMMAND_OK); + + crows = PQcmdTuples(r); + if( crows ) + log << log1 << "Db: deleted dir: " << id << " (deleted: " << atol(crows) << " rows)" << logend; + } + catch(const Error & e) + { + result = e; + } + + ClearResult(r); + + +return result; +} + + + bool Db::DelItemDelItem(const Item & item) { diff --git a/core/db.h b/core/db.h index 6c3a723..7c24400 100755 --- a/core/db.h +++ b/core/db.h @@ -53,6 +53,8 @@ public: bool GetPriv(Item & item, long id); Error EditPrivById(Item & item, long id); + Error DelDirById(long id); + bool DelItem(const Item & item); void GetDirs(DirContainer & dir_table); void GetUsers(UGContainer & user_table); diff --git a/core/dircontainer.cpp b/core/dircontainer.cpp index 3f373a3..da6e17a 100755 --- a/core/dircontainer.cpp +++ b/core/dircontainer.cpp @@ -22,8 +22,8 @@ DirContainer::Iterator DirContainer::GetRoot() { if( !is_root ) return table.end(); - -return table.begin() + root_index; + +return root_iter; } @@ -54,31 +54,26 @@ bool DirContainer::Empty() void DirContainer::PushBack(const Item & item) { -bool rebuild_indexes = false; - - if( table.size() == table.capacity() ) - rebuild_indexes = true; - - - if( item.parent_id == -1 ) + if( item.parent_id == -1 && is_root ) { - if( is_root ) - log << log1 << "DirCont: more than one root dir - skipped, id: " << item.id << logend; - else - { - is_root = true; - root_index = table.size(); - } + log << log1 << "DirCont: more than one root dir - skipped, id: " << item.id << logend; + return; } - table.push_back(item); - log << log2 << "DirCont: added dir, url: " << item.url << ", id: " << item.id << ", parent_id: " << item.parent_id << logend; - + Iterator last_iter = table.insert(table.end(), item); - if( rebuild_indexes ) - RebuildIndexes(); - else - AddIndexes( --table.end() ); + if( item.parent_id == -1 ) + { + is_root = true; + root_iter = last_iter; + } + + log << log2 << "DirCont: added dir, url: " << item.url << ", id: " << item.id << ", parent_id: " << item.parent_id << logend; + + table_id.insert( std::make_pair(last_iter->id, last_iter) ); + table_parent.insert( std::make_pair(last_iter->parent_id, last_iter) ); + + log << log3 << "DirCont: added indexes to dir, id: " << last_iter->id << ", parent_id: " << last_iter->parent_id << logend; } @@ -90,6 +85,7 @@ void DirContainer::Clear() table.clear(); table_id.clear(); table_parent.clear(); + is_root = false; } @@ -107,34 +103,6 @@ return i->second; - -void DirContainer::AddIndexes(Iterator item) -{ - table_id.insert( std::make_pair(item->id, item) ); - table_parent.insert( std::make_pair(item->parent_id, item) ); - - log << log2 << "DirCont: added indexes to dir, id: " << item->id << ", parent_id: " << item->parent_id << logend; -} - - -void DirContainer::RebuildIndexes() -{ -Iterator i; - - log << log2 << "DirCont: rebuilding indexes" << logend; - - table_id.clear(); - table_parent.clear(); - - for(i=table.begin() ; i!=table.end() ; ++i) - AddIndexes( i ); - - log << log2 << "DirCont: indexes rebuilt, table.size: " << table.size() << ", table_id.size: " << table_id.size() << ", table_parent.size: " << table_parent.size() << logend; -} - - - - DirContainer::ParentIterator DirContainer::ParentBegin() { return table_parent.begin(); @@ -184,3 +152,56 @@ DirContainer::ParentIterator DirContainer::NextParent(ParentIterator i) return i; } + + + + + +bool DirContainer::DelById(long id) +{ + TableId::iterator i = table_id.find(id); + + if( i == table_id.end() ) + { + log << log1 << "DirCont: delete: there is no directory with id: " << id << logend; + return false; + } + + long parent_id = i->second->parent_id; + TableParent::iterator z = table_parent.lower_bound(parent_id); + bool found = false; + + for( ; z != table_parent.end() && z->first == parent_id ; ++z ) + { + if( z->second == i->second ) + { + log << log2 << "DirCont: deleted directory id: " << id << ", url: " << i->second->url; + + if( i->second->parent_id == -1 ) + { + log << log2 << " (root directory)"; + is_root = false; + } + + log << log2 << logend; + + table.erase(i->second); + + log << log3 << "DirCont: deleted indexes into directory id: " << id << logend; + table_id.erase(i); + table_parent.erase(z); + + found = true; + break; + } + } + + if( !found ) + { + log << log1 << "DirCont: can't find an index_parent into directory id: " << id << ", url: " << i->second->url << " (deleting skipped)" << logend; + return false; + } + + +return true; +} diff --git a/core/dircontainer.h b/core/dircontainer.h index 050f51d..b2e10e9 100755 --- a/core/dircontainer.h +++ b/core/dircontainer.h @@ -10,7 +10,7 @@ #ifndef headerfiledircontainer #define headerfiledircontainer -#include +#include #include #include "item.h" #include "log.h" @@ -20,9 +20,9 @@ class DirContainer { public: - typedef std::vector Table; - typedef Table::iterator Iterator; - typedef Table::size_type SizeType; + typedef std::list Table; + typedef Table::iterator Iterator; + typedef Table::size_type SizeType; typedef std::map TableId; typedef std::multimap TableParent; @@ -43,6 +43,8 @@ public: Iterator FindId(long id); + bool DelById(long id); + ParentIterator ParentBegin(); ParentIterator ParentEnd(); ParentSizeType ParentSize(); @@ -53,17 +55,14 @@ public: private: - void AddIndexes(Iterator item); - void RebuildIndexes(); - // main table with dirs Table table; // true if there is a root dir in the table bool is_root; - // root dir - SizeType root_index; + // root + Iterator root_iter; // indexes TableId table_id; diff --git a/core/dirs.cpp b/core/dirs.cpp index e3369c7..bc255c3 100755 --- a/core/dirs.cpp +++ b/core/dirs.cpp @@ -19,23 +19,27 @@ void Dirs::Clear() void Dirs::CheckRootDir() { -DirContainer::ParentIterator i; -long roots = 0; - - - for( i=dir_table.FindFirstParent(-1) ; i!=dir_table.ParentEnd() ; i=dir_table.NextParent(i) ) - ++roots; - - if( roots == 0 ) + DirContainer::Iterator i = dir_table.GetRoot(); + + if( i != dir_table.End() ) + return; + + log << log1 << "Dirs: there is no a root dir in the database (creating one)" << logend; + + Item root; + + root.type = Item::dir; + root.parent_id = -1; + root.user_id = -1; + root.group_id = -1; + root.privileges = 0755; + root.default_item = -1; + + // !! upewnic sie ze baza nie zmieni url (gdyby wczesniej juz byl w bazie pusty url) + // !! zrobic jakis wyjatek do wprowadzania roota? + if( db.AddItem(root) == Error::ok ) { - log << log1 << "Dirs: there is no a root dir in the database" << logend; - Clear(); - } - else - if( roots > 1 ) - { - log << log1 << "Dirs: there are more than one root dir in the database" << logend; - Clear(); + dir_table.PushBack(root); } } @@ -372,3 +376,30 @@ void Dirs::SplitPath(const std::string & path, std::string & dir, std::string & if( i < path.size() - 1 ) file.assign(path, i+1, path.size() - i - 1); } + + + + + + + + + +void Dirs::DeleteDir(long id) +{ + DirContainer::ParentIterator pnext, p = dir_table.FindFirstParent(id); + + for( ; p != dir_table.ParentEnd() ; p = pnext ) + { + // this iterator p will be deleted by the next DeleteDir(p->second->id) + // (the next iterator we must calculate beforehand) + pnext = dir_table.NextParent(p); + + DeleteDir(p->second->id); + } + + if( db.DelDirById(id) == Error::ok ) + dir_table.DelById(id); +} + + diff --git a/core/dirs.h b/core/dirs.h index 98038bb..3aed0d9 100755 --- a/core/dirs.h +++ b/core/dirs.h @@ -24,19 +24,6 @@ class Dirs { - -private: -public: // !! temporarily - - - DirContainer dir_table; - - bool ExtractName(const char * & s, std::string & name); - void CheckRootDir(); - - - - public: void Clear(); @@ -86,6 +73,20 @@ public: static void SplitPath(const std::string & path, std::string & dir, std::string & file); + + void DeleteDir(long id); + + + void CheckRootDir(); + + +private: + + DirContainer dir_table; + + bool ExtractName(const char * & s, std::string & name); + + }; diff --git a/core/done.h b/core/done.h index 8cbae1c..47bde76 100755 --- a/core/done.h +++ b/core/done.h @@ -23,6 +23,7 @@ public: added_item, edited_item, deleted_item, + deleted_dir, privileged_item, added_dir, defaulted_dir, diff --git a/core/error.h b/core/error.h index ecb28d2..620f1de 100755 --- a/core/error.h +++ b/core/error.h @@ -43,7 +43,7 @@ public: no_function, // !! zamienic na no_function item_required, // !! zamienic na no_item (i usunac db_no_item) - + unknown_param, unknown = 1000 diff --git a/core/functionparser.cpp b/core/functionparser.cpp index bfc9e2c..951e905 100755 --- a/core/functionparser.cpp +++ b/core/functionparser.cpp @@ -33,6 +33,7 @@ void FunctionParser::ParseDirectories() return; } + while( true ) { request.dir_table.push_back( pdir ); diff --git a/core/session.cpp b/core/session.cpp index 87d2b2f..13e8754 100755 --- a/core/session.cpp +++ b/core/session.cpp @@ -31,6 +31,8 @@ void Session::Clear() done_status = Error::ok; item.Clear(); done_timer = 0; + + dir_old.clear(); } @@ -72,5 +74,8 @@ void Session::CheckTimers() } } - - +void Session::IncrementTimersIfExist() +{ + if( done_timer != 0 ) + ++done_timer; +} diff --git a/core/session.h b/core/session.h index 035a584..99af29b 100755 --- a/core/session.h +++ b/core/session.h @@ -49,6 +49,8 @@ struct Session Item item; + std::string dir_old; + // ------------------- Session(); @@ -57,6 +59,7 @@ struct Session bool operator<(const Session & s) const; bool DecTimer(int & timer); void CheckTimers(); + void IncrementTimersIfExist(); }; diff --git a/templates/dir.cpp b/templates/dir.cpp index e28a5f1..d070691 100755 --- a/templates/dir.cpp +++ b/templates/dir.cpp @@ -169,6 +169,11 @@ void dir_last_default_item_url(Info & i) +void dir_old(Info & i) +{ + HtmlEscape(i.out, request.session->dir_old); + +} diff --git a/templates/done.cpp b/templates/done.cpp index d9ad0ce..231153f 100755 --- a/templates/done.cpp +++ b/templates/done.cpp @@ -79,6 +79,11 @@ void done_added_dir(Info & i) } +void done_deleted_dir(Info & i) +{ + i.result = request.session->done == Done::deleted_dir; +} + void done_defaulted_dir(Info & i) diff --git a/templates/templates.cpp b/templates/templates.cpp index 9032009..eb21f85 100755 --- a/templates/templates.cpp +++ b/templates/templates.cpp @@ -131,6 +131,7 @@ Ezc::Pattern * p = 0; case Error::db_no_item: case Error::no_function: + case Error::unknown_param: p = &pat_err_404; break; @@ -241,6 +242,8 @@ void Templates::CreateFunctions() functions.Insert("dir_last_default_item_dir", dir_last_default_item_dir); functions.Insert("dir_last_default_item_url", dir_last_default_item_url); + functions.Insert("dir_old", dir_old); + /* user */ @@ -274,6 +277,7 @@ void Templates::CreateFunctions() functions.Insert("done_privileged_item", done_privileged_item); functions.Insert("done_loggedout", done_loggedout); functions.Insert("done_added_dir", done_added_dir); + functions.Insert("done_deleted_dir", done_deleted_dir); functions.Insert("done_defaulted_dir", done_defaulted_dir); @@ -347,7 +351,7 @@ void Templates::Read() pat_err_others.ParseFile("err_others.html"); pat_fun_who.Directory(data.templates); - pat_fun_who.ParseFile("who.html"); + pat_fun_who.ParseFile("fun_who.html"); CreateFunctions(); diff --git a/templates/templates.h b/templates/templates.h index 795e797..7089b99 100755 --- a/templates/templates.h +++ b/templates/templates.h @@ -114,6 +114,9 @@ namespace TemplatesFunctions void dir_last_default_item_dir(Info &); void dir_last_default_item_url(Info & i); + void dir_old(Info & i); + + /* user */ @@ -149,6 +152,7 @@ namespace TemplatesFunctions void done_privileged_item(Info & i); void done_added_dir(Info & i); + void done_deleted_dir(Info & i); void done_defaulted_dir(Info & i); void done_loggedout(Info & i);