# = Using sugoi-mail in your own web applications # # Sugoi-Mail provides a SOAP (and XMLRPC) API to let you embed it into # your own web appplication without using its own interface. (This is # handy if, for example, you want to make a Xoops or Drupal module for # it.) # # To use the web service, first you need to have a Domain account on # the server. Let's say that your domain is "example.com" and the # password for example.com is "example". # # You'd start a session with Sugoi-Mail by logging into the domain. I'm # going to use SOAP as my example API, with the assumption that you've # already had wsdl2ruby build a client library for you with. # *MAKE SURE THAT COOKIES ARE ENABLED IN YOUR SOAP CLIENT!* # # wsdl2ruby --wsdl http://sugoi-mail-server/wsdl --type client # # This being done, you'd connect like this: # # client = MailserviceMailservicePort.new # client.domainLogin "example.com", "example" # # This is how the web application logs in. Once the application is # logged in, then the user (let's keep the "example" theme going with a # username of "example" and a password of "password") can log in: # # client.userLogin "example", "password" # # Once the user's logged in, then your application can call the user_* # functions--for example, to retrieve the user's email address, use # the UserEmailAddress call: # # emailaddress = client.userEmailAddress # returns "example@example.com" # # # # If you log in as an "admin" user, then all of the admin_* messages are # also available to you. class MailserviceController < ApplicationController wsdl_service_name "Mailservice" web_service_api MailserviceApi web_service_scaffold :invoke private def domain_logged_in? raise "Not logged into domain" unless session[:domain_id] true end def user_logged_in? domain_logged_in? raise "Not logged in as user" unless session[:user_id] true end def user_admin? user_logged_in? raise "No privileges to perform that operation" unless \ User.find(session[:user_id]).domainadmin? true end # Verifies whether a mailing list belongs to the currently-logged-in # user or not. def my_mailing_list (mailinglist_id) user_logged_in? mailinglist = Mailinglist.find_by_id(mailinglist_id) raise "Mailing list not found" unless mailinglist unless session[:user_id] == mailinglist.user_id begin user_admin? rescue raise "Permission denied" end end mailinglist end public #======================================================================== # Server methods #======================================================================== # Use this to ensure that the SOAP connection is still alive and # responding. This and domain_logged_in are the only API methods # that don't require any kind of authentication. def ping true end #======================================================================== # domain methods #======================================================================== # Log into the domain. def domain_login domainname, password domain = Domain.authenticate(domainname, password) if domain session[:domain_id]=Domain.authenticate(domainname, password).id end domain_logged_in end # Log out of the domain. def domain_logout if session[:domain_id] then session[:domain_id] = nil true else false end end # Verify whether the domain is logged in or not. def domain_logged_in not session[:domain_id].nil? end # Returns the domain name. def domain_name Domain.find(session[:domain_id]).name end #======================================================================== # Administrator methods #======================================================================== # Returns true if the user is an administrator and false otherwise def is_admin user_admin? rescue false end # Creates a new user. NOTE: This method requires that you're # already signed in as an administrator. def admin_user_signup login, description, password, password_confirmation, mailinglist_admin, domain_admin user_admin? user=User.new user.login=login user.domain_id=session[:domain_id] user.password=password user.password_confirmation=password_confirmation user.mailinglistadmin = mailinglist_admin user.domainadmin = domain_admin if user.save then #this is a disgusting hack user.password = password user.password_confirmation = password_confirmation user.save user.mailinglist.description = description user.mailinglist.save return true else raise user.errors.sort.map { |e| "#{e[0]}: #{e[1]}" }.join("\n") end end # Returns all users in this domain. def admin_user_list user_admin? all_users=User.find_all_by_domain_id session[:domain_id] return all_users.map { |u| [ u.login, u.description ] } end # Returns all users in this domain, as a hash def admin_user_collection user_admin? all_users=User.find_all_by_domain_id session[:domain_id] return all_users end # Resets a user's password. def admin_user_reset_password login, password, password_confirmation user_admin? user=User.find_by_login login if user then user.password=password user.password_confirmation=password_confirmation if user.save then true else raise user.errors.sort.map { |e| "#{e[0]}: #{e[1]}" }.join("\n") end else raise "user: user not found" end end # Deletes a user. def admin_user_delete login, login_confirmation user_admin? if login_confirmation != login then raise "Login and login confirmation not the same" end if User.find(session[:user_id]).login == login then raise "Trying to delete yourself? Very funny" end u=User.find_by_login login if u then User.delete u.id return true else return false end end # Returns the confirmation code for a particular combination of # mailing list and address. # # This one should probably resend the confirmation message. def admin_get_confirmation_code mailinglist_name, address user_admin? m=Mailinglist.find_by_name(mailinglist_name) a=Address.find_by_address(address) c=Confirmationcode.find(:first,:conditions => [ 'mailinglist_id = ? and address_id = ?', m.id, a.id ]) return c.code end # Returns all mailing lists in this domain. def admin_mailinglists_all user_admin? Mailinglist.find_all_by_domain_id session[:domain_id] end #======================================================================== # user methods #======================================================================== # Logs the user in. If the user logs in successfully, returns true, # otherwise false. def user_login username, password domain_logged_in? session[:user_id] = nil user = User.authenticate username, password if user session[:user_id]=user.id end user_logged_in end # Logs the user out. def user_logout; session[:user_id] = nil; end # Returns whether the user is logged in or not. def user_logged_in; not session[:user_id].nil?; end # Returns the user's username. def user_name; User.find(session[:user_id]).login; end # Returns all the mailing lists that belong to this user. def user_mailinglists user_logged_in? Mailinglist.find_all_by_user_id(session[:user_id]) - [ User.find(session[:user_id]).mailinglist ] end # Returns the user's email address. def user_email_address user_logged_in? User.find(session[:user_id]).address end # Returns all addresses belonging to this user. def user_email_addresses user_logged_in? User.find(session[:user_id]).addresses.map { |a| a.address } end # Returns all _confirmed_ email addresses belonging to this user def user_email_addresses_confirmed user_logged_in? User.find(session[:user_id]).mailinglist . confirmed_addresses.map { |a| a.address } end # Returns all yet-to-be-confirmed email addresses belong to this # user. def user_email_addresses_unconfirmed user_logged_in? User.find(session[:user_id]).mailinglist . pending_addresses.map { |a| a.address } end # Allows the user to confirm his email address on the web instead of # by email. def user_email_address_confirm(address,code) user_logged_in? address_obj=Address.find_by_address(address) ml=User.find(session[:user_id]).mailinglist if ml.confirm(address_obj,code) then ml.save else false end end # Lets the user change his password. def user_change_password(old_password, password, password_confirmation) user_logged_in? user=User.find(session[:user_id]) if User.authenticate(user.login, old_password) then user.password=password user.password_confirmation=password_confirmation if(user.save) return true else errstr = user.errors.sort.map do |fac,err| "#{fac}: #{err}" end.join("\n") raise RuntimeError, errstr end else raise "auth: original password incorrect" end end # Returns the user's real name. def user_real_name user_logged_in? User.find(session[:user_id]).description end # Allows the user to change his real name. def user_change_real_name password, new_name user_logged_in? user=User.find(session[:user_id]) if User.authenticate(user.login, password) then ml = user.mailinglist ml.description=new_name if ml.save return new_name else errstr = ml.errors.sort.map do |fac, err| "#{fac}: #{err}" end.join("\n") raise RuntimeError, errstr end else raise "auth: password incorrect" end end # Adds a new email address to this user. def user_email_addresses_add(address) user_logged_in? user = User.find(session[:user_id]) if user.mailinglist.subscribe address then user.mailinglist.save end user.mailinglist.addresses end # Removes an email address from the user's email address list. def user_email_addresses_remove(address) user_logged_in? User.find(session[:user_id]).mailinglist.unsubscribe address end # Creates a mailing list of type +mailinglist_class+. Retrieve the # list of valid mailing list classes with mailinglist_classes. def mailinglist_create mailinglist_name, mailinglist_class user_logged_in? mailinglist_class_id = MailinglistClass.find_by_name mailinglist_class unless mailinglist_class_id raise "Class does not exist (check MailinglistClasses for list)" end m=Mailinglist.new(:name => mailinglist_name, :mailinglist_class_id => mailinglist_class_id.id, :user_id => session[:user_id]) m.save end # Returns a list of the names of all the mailing list classes. def mailinglist_classes # the first mailing list class is special (it's reserved for # forwarding addresses). MailinglistClass.find(:all, :conditions => "id > 1").map { |mlc| mlc.name } end # Returns the attributes of the mailing list class +mlclass+. Use # mailinglist_classes to retrieve a list of mailing list class # names. def mailinglist_class_get_attributes(mlclass) MailinglistClass.find_by_name mlclass end # Returns the name of the mailing list with id +id+ def mailinglist_name id my_mailing_list(id).name end # Returns the email address of the mailing list with id +id+ def mailinglist_address id my_mailing_list(id).address end # Returns the id of the mailing list with name +name+. The converse # of mailinglist_name def mailinglist_find_by_name name user_logged_in? m=Mailinglist.find_by_address \ "#{name}@#{Domain.find(session[:domain_id]).name}" if m then m[0].id end end # Deletes a mailing list if you're allowed to do that. def mailinglist_delete mailinglist_id m=my_mailing_list(mailinglist_id) if m.destroy true end end # Returns a list of addresses on a mailing list. def mailinglist_subscribers mailinglist_id mailinglist=my_mailing_list(mailinglist_id) mailinglist.confirmed_addresses.each do |addr| addr.address end end # Returns a list of non-confirmed addresses on a mailing list. def mailinglist_pending mailinglist_id mailinglist=my_mailing_list(mailinglist_id) mailinglist.pending_addresses.map do |addr| addr.address end end # Adds an address to a mailing list. If the mailing list requires # confirmation, then the confirmation code will be emailed to # +address+. def mailinglist_subscribe mailinglist_id, address if my_mailing_list(mailinglist_id).subscribe(address) true end end # Confirms a subscription to a mailing list. Returns false if the # confirmation code was incorrect. def mailinglist_confirm mailinglist_name, address, code addr = Address.find_by_address address mailinglist = Mailinglist.find_by_name mailinglist_name return false if addr == nil or mailinglist == nil # This redundant-looking if is to ensure that it returns only # "true" or "false", and not a not-true-but-still-evaluated-as- # truth value like a mailing list, or a not-false such as nil. if mailinglist.confirm(addr, code) true else false end end # Removes an address from a mailing list. def mailinglist_unsubscribe mailinglist_id, address if my_mailing_list(mailinglist_id).unsubscribe(address) true end end # Removes an address from a mailing list without sending the # farewell message def mailinglist_unsubscribe_quiet mailinglist_id, address if my_mailing_list(mailinglist_id).unsubscribe(address, false) true end end end ## TODO: implement message-handling functionality properly ## #======================================================================== ## # Message methods ## #======================================================================== ## ## # Returns the IDs of all the messages messages sent to this mailing ## # list. ## # ## # This should probably do something more useful like return all ## # new messages since some datestamp or something. ## def mailinglist_messages mailinglist_id ## my_mailing_list(mailinglist_id).messages ## end ## ## # Returns the message with the id +id+. ## def message message_id ## readable_message(id) ## end ## ## # Return the message that this one's a response to. ## def message_parent message_id ## readable_message(id).parent ## end ## ## # Returns all responses to this message. ## def message_responses message_id ## readable_message(id).children.map { |m| m.id } ## end