Can not set :DELETE flag on GMail Inbox using rails mail gem - ruby-on-rails

I am getting this error when trying to set the deleted flag;
Net::IMAP::NoResponseError (STORE attempt on READ-ONLY folder (Failure))
The error is thrown when running this;
connector.uid_store(item_uid, "+FLAGS", [:Deleted])
This code runs fine just before it;
connector.create("TestFolder") unless connector.list('', "TestFolder")
connector.uid_copy(item_uid, "TestFolder")
I have not been able to find a reason for this, especially since I can create 'folders' and copy items to it without a problem.
I am using ruby 1.9.2, rails 3.2.10, mail 2.4.4
Any help would really save my mind.
Cheers
~~~~~~~ edit
Mail defaults are setup as per below;
#==> Collect items
case feed.url_type
when "IMAP"
puts "Trying IMAP retriever for " + feed.url_source
Mail.defaults do
retriever_method :imap,
:address => feed.url_source,
:port => 993,
:user_name => feed.user,
:password => feed.password,
:enable_ssl => true,
:read_only => false
end
self.add_email_stubs(Mail.find(), feed)
The connector is picked up from here;
def add_email_stubs(items, feed)
Mail.all do |item, connector, item_uid|
and used here (in same def);
#==> Move message
connector.create("Archive") unless connector.list('', "Archive")
connector.uid_copy(item_uid, "Archive")
connector.uid_store(item_uid, "+FLAGS", [:Deleted]) <==Error occurs here

Fixed...
I needed to explicitly select the INBOX before it would allow me to make any STORE changes.
You can not rely on defaulting to the INBOX when connecting, even though it looks like you 'in' the INBOX.
connector.uid_copy(item_uid, "Archive")
connector.select("INBOX") <== Need to explicitly select the INBOX
connector.uid_store(item_uid, "+FLAGS", [:Deleted])
Thats to tricky for a screw driver monkey like me to have to work out!! :)

Related

Ruby-Rails net-ldap search

I want to be able to determine if a user is a memberOf a specific group as well as a couple other attributes available on the active directory. I know that the authentication and binding is working as intended, however, I keep getting two warnings:
warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
warning: The called method tcp is defined here
Since these are warnings, I wouldn't expect them to affect the output that I'm looking for.
I want to list out the attributes and the values for the search query, but when I run the code, I get the warnings, followed by "Bind succeeded!", and then the program finishes executing. I've tried changing the query, changing the attributes that I'm searching for, and ensuring that they were named correctly. I have posted the code below:
ldap = Net::LDAP.new :host => HOST, # your LDAP host name or IP goes here,
:port => PORT, # your LDAP host port goes here,
:encryption => :simple_tls,
:base => BASE# the base of your AD tree goes here,
:auth => {
:method => :simple,
:username => "#{login}##{myDomain}", # a user w/sufficient privileges to read from AD goes here,
:password => PASSWORD # the user's password goes here
}
search_param = #username
result_attrs = ["sAMAccountName", "displayName", "mail", "memberOf"] # Whatever you want to bring back in your result set goes here
# Build filter
search_filter = Net::LDAP::Filter.eq("sAMAccountName", search_param)
# Execute search
if ldap.bind
puts "Bind succeeded!"
ldap.search(:filter => search_filter, :attributes => result_attrs) do |entry|
puts "DN: #{entry.dn}"
entry.each do |attr, values|
puts ".......#{attr}:"
values.each do |value|
puts "#{value}\n"
end
end
end
else
puts "Failure to bind"
end
A couple problems I feel could be causing this issue is that I don't have the required authentication to search for users in the directory, or the users don't exist (I am searching for my own username, so it should exist, therefore I'm leaning to first theory). Thank you!

How to create a multipart ical email? [Rails]

What I want to achieve is the following:
Send an email with delayed_job containing:
plain-text
html (will be displayed by regular clients which don't understand the inline ical)
"inline" ical which is recognized by Outlook and Thunderbird (with Lightning).
a "regular" ical attachment (for #2)
What works so far/what does'nt:
I am able to send the email via delayed_job with all parts, however:
in Apple's Mail 2 attachments show up (instead of one):
(the html is displayed fine)
in Thunderbird (Lightning) I do get an invitation, just like I want. But the Alarm does not show up.
I have to do some REALLY disgusting gsubs on the rendered iCal in order for the ATTENDEES to show up. (see code snippet)
My thinking:
The first thing to keep in mind is: in order to send an email with attachments from delayed_job
To fix this, remember to add this line to your mailer: content_type "multipart/mixed"
As far as I understand the correct MIME-Type hierarchy would therefore be:
multipart/mixed
multipart/alternative
text/plain
text/html
text/calendar (with: method=REQUEST)
application/ics
Warning! code incoming.
I currently construct this email in the following manner:
Edit: I updated the mailer for Rails 4.2 (attachments must be placed before mail)
in my mailer.rb
def invitation_email(...)
subject = "I suck at email..."
attachments["invite.ics"] = { mime_type: "application/ics",
content: ical_attachment }
email = mail(from: me, to: you, subject: subject)
add_ical_part_to(email)
email
end
def add_ical_part_to(mail)
outlook_body = ical_attachment
mail.add_part(Mail::Part.new do
content_type "text/calendar; method=REQUEST"
body outlook_body
end)
end
and this is how I construct the ical attachments:
def ical_attachment
params_participant = {
"ROLE" => "REQ-PARTICIPANT",
"RSVP" => "FALSE",
"PARTSTAT" => "ACCEPTED"
}
params_invite = {
"CUTYPE" => 'INDIVIDUAL',
"ROLE" => "REQ-PARTICIPANT",
"PARTSTAT" => "NEEDS-ACTION",
"RSVP" => "TRUE"
}
cal = Icalendar::Calendar.new
event = Icalendar::Event.new
event.dtstart #party.from.to_datetime, { "VALUE" => "DATE" }
event.dtend #party.to.to_datetime, { "VALUE" => "DATE" }
event.summary #party.title
event.description #party.description
event.klass "PRIVATE"
event.organizer "cn=#{#user.name} #{#user.surname}:mailto:#{#user.email}"
# THIS DOES NOT WORK
event.alarm.trigger = "-PT5M" # 5 Minutes before...
#party.participations.each do |participation|
str = "cn=#{participation.user.name} #{participation.user.surname}:mailto:#{participation.user.email}"
event.add_attendee(str, params_participant)
end
#party.invitations.each do |invitee|
event.add_attendee("mailto:#{invitee.email}", params_invite)
end
cal.add_event(event)
cal.publish
# I KNOW THIS IS HORRIBLE AND I HATE IT, BUT OTHERWISE THE ATTENDEES DO NOT SHOW UP
cal.to_ical.gsub("ORGANIZER:", "ORGANIZER;").gsub("ACCEPTED:", "ACCEPTED;").gsub("TRUE:", "TRUE;").gsub("PUBLISH", "REQUEST")
end
Any help would be really appreciated!
The email that is being generated: http://pastebin.com/patf05zd
Oh and I'm on:
Rails 3.2.13
The Icalendar gem I'm using
In case someone else happens to come across this, here is what I did:
Instead of the icalendar gem I now use ri_cal. Although I was skeptical because the last commit to that repo was 3 years ago, the google group was a very helpful resource.
Here is how I generate the ical attachment (both inline and normal), which seems to be working fine (although it obviously needs some refactoring :))
def to_ical
# this is horrible
klass = self
cal = RiCal.Calendar do
event = event do
organizer "CN=#{klass.user.name} #{klass.user.surname}:mailto:#{klass.user.email}"
summary klass.party.title
description klass.ical_description
dtstart klass.party.from.utc.to_datetime
dtend klass.party.to.utc.to_datetime
location "See url in description"
security_class klass.security_class
# this is horrible
h = self
klass.party.participations.each do |participation|
h.add_attendee klass.prepare_participant(participation)
end
klass.party.invitations.each do |invitee|
h.add_attendee klass.prepare_invitee(invitee.email)
end
unless klass.party.reminder == 0
alarm do
description "Alarm description"
trigger klass.convert_trigger # -PT1H
action "DISPLAY"
end
end
end
end
# THE HORROR
cal.to_s.gsub("ATTENDEE:", "ATTENDEE")
.gsub("ORGANIZER:", "ORGANIZER;")
.gsub("CALSCALE:GREGORIAN", "CALSCALE:GREGORIAN\nMETHOD:REQUEST\n")
end
The 2 Attachments in Apples Mail still show up, I don't think that can be fixed.
Your second B64 encoded attachment contains a lot of garbage towards the end (attendee field).
That would explain the Thunderbird issue.
Please note that some clients will ignore any alarm you may set on a REQUEST: As an organizer, you should not dictate when each attendee should be reminded of the meeting. That would be a rather rude thing to do.
Regarding the Apple iCal issue, there is not much you can do I'm afraid: Some clients want the ics within, some as an attachment so you have to provide both. Does it show the accept/decline panel on iCal ?

Amazon Mechanical Turk - Rturk - RestClient::BadRequest: 400 Bad Request

I'm trying to set up Rturk to outsource some work to Amazon's Mechanical Turk. When I try to create my HITs, I keep running into t he following error in console:
RestClient::BadRequest: 400 Bad Request
When I copy the URL and paste it in my browser to get the response, I get the following message:
This user is not authorized to perform the requested operation
Do you guys have any idea what could be happening here? I am following the rturk documentation on github. https://github.com/mdp/rturk Is it possible that the gem has to be updated?
RTurk.setup(ENV['AWS_ACCESS_KEY_ID'], ENV['AWS_SECRET_ACCESS_KEY_ID'], :sandbox => true)
hit = RTurk::Hit.create(
:title => "Sample turk",
:assignments_duration => 1.hour,
:expires_at => 1.day.from_now
) do |hit|
hit.lifetime = 1.day
hit.assignments = 1
hit.description = "Test description."
hit.keywords = "places, search, map, location"
hit.question(mturk-fb_path, :frame_height => 750)
hit.reward = reward
if approval_rate
hit.qualifications.add :approval_rate, { :gt => approval_rate }
end if abandoned_rate
hit.qualifications.add :abandoned_rate, { :lt => abandoned_rate }
end
if is_us
hit.qualifications.add :country, { :eql => "US" }
end
end
}
A couple things might be going on here:
I don't believe :assignments_duration and :expires_at are valid options. You should be using hit.duration to specify the amount of time a worker has to complete a hit once they accept it and hit.lifetime to set the amount of time until the hit will expire.
It might just be a typo in your post, but mturk-fb_path is not a valid ruby variable name. (can't use a dash)
Try starting off with the simplest example that you can build off of once you get it working. This example from rturk should be a good start: https://github.com/mdp/rturk#creating-hits.
Also, I definitely recommend reading through the mturk docs for creating a hit: http://docs.aws.amazon.com/AWSMechTurk/2011-10-01/AWSMturkAPI/ApiReference_CreateHITOperation.html.

Rails: finding database records

In order to improve my understanding of Rails, I'm converting a Sinatra app that uses data_mapper.
I'm trying to find the best replacements for data mappers 'first' method that searches database and returns first instance of the record sought.
Can anyone comment if this is done right, or if there's a better solution?
Situation #1
Sinatra
url = Url.first(:original => original)
Rails (both of these ok?)
url = Url.find_by_original(original) #this find_by_original
url = Url.where(:first_name => 'original')
situation #2
Sinatra
raise 'Someone has already taken this custom URL, sorry' unless Link.first(:identifier => custom).nil?
My Rails (with find)
raise 'Someone has already taken this custom URL, sorry' unless Link.find(:identifier => custom).nil? #this Link.find
Original context was a method that shortens urls
def self.shorten(original, custom=nil)
url = Url.first(:original => original)
return url.link if url
link = nil
if custom
raise 'Someone has already taken this custom URL, sorry' unless Link.first(:identifier => custom).nil?
raise 'This custom URL is not allowed because of profanity' if DIRTY_WORDS.include? custom
transaction do |txn|
link = Link.new(:identifier => custom)
link.url = Url.create(:original => original)
link.save
end
else
transaction do |txn|
link = create_link(original)
end
end
return link
end
You can just use a validator on the model. Just do a validates_uniqueness_of :first_name in the Url model (app/models/url.rb). There are also other validations available in the Rails guides
EDIT
If you really want to find if such a record exists manually. You can just do Url.find(:first, :conditions => { :first_name => 'original' }) and check for nil
raise 'Someone has already taken this custom URL, sorry' unless Link.find(:first, :conditions => { :identifier => custom }).nil?
Also, if you are new to rails might want to look at the query interface. Personally, I like to use the squeel gem so my queries are strictly ruby instead of mixing ruby and sql statements.

What's the most efficient way to keep a user database in sync with an external mailing list service?

I'd like some advice on how I should synchronize a list of email addresses on 11k users against an external mailing list program, in this case Mailchimp.
Normally the way I'd do this is simply to have an :after_save callback, to send a single update to the external api.
But already each hour, a rake task is run to update a property on every user in the database. If I simply did that, every hour, the the poor mailchimp API would get be hit 11,000 times.
What's the most efficient, simple way to do this, to check only if a single attribute you're watching has changed from what it was before the save?
If there's a variable that persists across the transaction lifecycle I would simply do something like this, where I check if the value has changed, and if it's different execute come other code.
class User
:before_save :store_old_email
:after_save :sync_with_chimp
def store_old_email
$ugly_of_global_variable_to_store_email = user.email
end
:sync_with_chimp
if $ugly_of_global_variable_to_store_email != user.email
//update_mail_chimp_api
end
end
end
I've checked the rails api here, and I'm still slightly unclear on how I should be doing this.
Would you use the dirty? class here to do this?
This is the way I went with in the end.
It turns out Rails gives you loads of handy callbacks in the dirty to do this.
Any suggestions on how to make this code less repetitive wold be gratefully received.
def update_mailchimp(optin)
# Create a Hominid object (A wrapper to the mailchimp api), and pass in a hash from the yaml file
# telling which mailing list id to update with subscribe/unsubscribe notifications)
#hominid = Hominid.new
client_site_list_id = YAML.load(File.read(RAILS_ROOT + "/config/mailchimp.yml"))
case optin
when 'subscribe_newsletter'
logger.debug("subscribing to newsletter...")
"success!" if #hominid.subscribe(client_site_list_id['client_site_to_mailchimp_API_link'], email, {:FNAME => first_name, :LNAME => last_name}, 'html')
when 'unsubscribe_newsletter'
logger.debug("unsubscribing from newsletter...")
"success!" if #hominid.subscribe(client_site_list_id['client_site_to_mailchimp_API_link'], email, {:FNAME => first_name, :LNAME => last_name}, 'html')
when 'subscribe_monthly_update'
logger.debug("subscribing to monthly update...")
"success!" if #hominid.subscribe(client_site_list_id['monthly_update'], email, {:FNAME => first_name, :LNAME => last_name}, 'html')
when 'unsubscribe_monthly_update'
logger.debug("unsubscribing from monthly update...")
"success!" if #hominid.unsubscribe(client_site_list_id['monthly_update'], email, {:FNAME => first_name, :LNAME => last_name}, 'html')
end
end
# Keep the users in sync with mailchimp's own records - by only firing requests to the API if details on a user have changed after saving.
def check_against_mailchimp
logger.info("Checking if changes need to be sent to mailchimp...")
if newsletter_changed?
logger.info("Newsletter changed...")
newsletter ? update_mailchimp('subscribe_newsletter') : update_mailchimp('unsubscribe_newsletter')
end
if monthly_update_changed?
logger.info("update preferences changed...")
monthly_update ? update_mailchimp('subscribe_monthly_update') : update_mailchimp('unsubscribe_monthly_update')
end
end
you could change your users model to an active resource instead of active record and just use mailchimps api as your db for users
this is an older post about active resource but might get you started down the right path
http://www.therailsway.com/2007/9/3/using-activeresource-to-consume-web-services

Resources