require 'pg' require 'common/postfixadmin_plugin' require 'rm/rm_plugin' # Handle the removal of users and domains from the Postfixadmin database. # class PostfixadminRm include PostfixadminPlugin include RmPlugin # Remove *user* from the Postfixadmin database. This should remove # him from _every_ table in which he is referenced. Unfortunately, # Postfixadmin does not use foreign keys or ON DELETE CASCADE # triggers so we need to delete the associated child table records # ourselves. # # @param user [User] the user to remove. # def remove_user(user) raise NonexistentUserError.new(user.to_s()) if not user_exists(user) # Remove aliases FROM our user to some other address. sql_queries = ['DELETE FROM alias WHERE address = $1;'] # Also delete aliases that point SOLELY TO our user. sql_queries << "DELETE FROM alias WHERE goto = $1;" # But aliases don't need to point to a single user! If our user # was part of a multi-recipient alias, we want to remove our user # from the alias and leave the other recipients. # # We want to delete the comma that precedes/follows the address, # too. Since the address to be replaced can appear at either the # beginning or the end of the list (as well as in the middle), we # have to try to fix both cases: comma before, and comma after. comma_before = "CONCAT(',', $1)" comma_after = "CONCAT($1, ',')" sql_queries << "UPDATE alias SET goto=REPLACE(goto, #{comma_before}, '');" sql_queries << "UPDATE alias SET goto=REPLACE(goto, #{comma_after}, '');" sql_queries << 'DELETE FROM mailbox WHERE username = $1;' sql_queries << 'DELETE FROM quota WHERE username = $1;' sql_queries << 'DELETE FROM quota2 WHERE username = $1;' sql_queries << 'DELETE FROM vacation WHERE email = $1;' # Should be handled by a trigger, according to PostfixAdmin code. sql_queries << 'DELETE FROM vacation_notification WHERE on_vacation = $1;' connection = PG::Connection.new(@db_hash) begin sql_queries.each do |sql_query| varchar = 1043 # from pg_type.h params = [{:value => user.to_s(), :type => varchar}] connection.query(sql_query, params) end ensure # Make sure the connection gets closed even if a query explodes. connection.close() end end # Remove *domain* from the Postfixadmin database. This should remove # the domain from _every_ table in which it is referenced. It should # also remove every user that belongs to the doomed domain # Postfixadmin has some experimental support for triggers, but they # don't do a very good job of cleaning up. Therefore we remove all # users in the domain manually before removing the domain itself. # # Log entries (from the "log" table) are not removed since they may # still contain valuable information (although they won't mention # this removal). # # @param domain [Domain] the domain to remove. # def remove_domain(domain) raise NonexistentDomainError.new(domain.to_s()) if not domain_exists(domain) # First remove all users belonging to the domain. This will handle # alias updates and all the sensitive crap we need to do when # removing a user. users = list_domains_users([domain]) users.each { |u| remove_user(u) } # The domain_admins table contains one record per domain # (repeating the user as necessary), so this really is sufficient. sql_queries = ['DELETE FROM domain_admins WHERE domain = $1;'] # Some of the following queries should be redundant now that we've # removed all users in the domain. sql_queries << 'DELETE FROM alias WHERE domain = $1;' sql_queries << 'DELETE FROM mailbox WHERE domain = $1;' sql_queries << 'DELETE FROM alias_domain WHERE alias_domain = $1;' sql_queries << 'DELETE FROM vacation WHERE domain = $1;' sql_queries << 'DELETE FROM domain WHERE domain = $1;' connection = PG::Connection.new(@db_hash) begin sql_queries.each do |sql_query| connection.query(sql_query, [domain.to_s()]) end ensure # Make sure the connection gets closed even if a query explodes. connection.close() end end end