class PostfixadminRm

Handle the removal of users and domains from the Postfixadmin database.

Public Instance Methods

remove_domain(domain) click to toggle source

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.

# File lib/rm/plugins/postfixadmin.rb, line 81
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.sync_exec_params(sql_query, [domain.to_s()])
    end
  ensure
    # Make sure the connection gets closed even if a query explodes.
    connection.close()
  end
end
remove_user(user) click to toggle source

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.

# File lib/rm/plugins/postfixadmin.rb, line 23
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.sync_exec_params(sql_query, params)
    end
  ensure
    # Make sure the connection gets closed even if a query explodes.
    connection.close()
  end
end