How to reply gmail using Gmail API in the same thread_id - ruby

Hi guys currently i'm building reply message using ruby, here is my code
def reply(user_id, subject, to, body, thread_id)
client = google_client user_id
token = Token.find_by_user_id(user_id)
access_token = token.access_token
gmail = Google::Apis::GmailV1::GmailService.new
gmail.authorization = client
message = Mail.new
message.date = Time.now
message.subject = "#{subject}"
message.from = token.email
message.to = "#{to}"
message.thread_id = "#{thread_id}"
message.part content_type: 'multipart/alternative' do |part|
part.html_part = Mail::Part.new(body: "#{body}", content_type: 'text/html; charset=UTF-8')
end
# attach file
open('/Users/jaisanasrulloh/Downloads/image.png') do |file|
message.attachments['image.jpg'] = file.read
end
msg = message.encoded
message_object = Google::Apis::GmailV1::Message.new(raw:message.to_s)
gmail.send_user_message('me', message_object)
end
but i got error like below:
NoMethodError: undefined method `thread_id=' for #<Mail::Message:0x007fcedb6b9c78>
My question is how to add thread_id inside Mail::Message object ? Some person using class RMail::Message like this one
is there exist parameter thread_id inside Mail::Message ? if there exist how to add it?

thread_id is a part of the Gmail message object not the Mail object.
Add it here
message_object = Google::Apis::GmailV1::Message.new(raw:message.to_s, thread_id:thread_id)
and remove this:
message.thread_id = "#{thread_id}"

Related

Mock method in class using MiniTest

I'm running into an issue mocking a method within a class using Ruby's MiniTest::Mock and stub feature and it's driving me insane. What I am trying to do is set up a way to get an access token by calling a Ruby API which will get the actual access token from a 3rd party site.
This is the class all work will be done in.
class ThisClass
attr_reader :hauler
def initialize(hauler)
#hauler = hauler
end
def get_access_token
access_token = Rails.cache.read("access_token_#{hauler.id}")
if access_token.blank?
access_token = ext_access_token
Rails.cache.write("access_token_#{#hauler.id}", access_token, { expires_in: 3600 })
end
access_token
end
def ext_access_token
# call to external url to get access_token
# Successful response will be { "data": { "authToken": "new-token"} }"
url = URI.parse("http://www.fake-login.com/auth/sign_in")
res = Net::HTTP.post_form(url, "userName" => #hauler[:client_id], "password" => #hauler[:client_secret])
json_response = JSON.parse(res.body)
json_response["data"]["authToken"]
end
end
The test is as follows
class ThisClassTest < ActiveSupport::TestCase
test "Get Access Token" do
hauler = haulers(:one)
tc = ThisClass.new(hauler)
mock_client = MiniTest::Mock.new
mock_client.expect :ext_access_token, "\"{ \"data\": { \"authToken\": \"new-token\"} }\""
ThisClass.stub(:ext_access_token, mock_client) do
puts tc.get_access_token
end
assert_equal true, true
end
end
When I run my tests, I get the following error
Error:
ThisClassTest#test_Get_Access_Token:
NameError: undefined method `ext_access_token' for class `ThisClass'
I'm clearly doing something wrong since all I want is for the ext_access_token method to return the same data string so I can run logic against it, but very much failing. ThisClass is fairly simplistic but outlines the setup I'll be going with moving forward for more complex methods based on the return from the external site.
The test can't find ext_access_token method because it's looking for a class method on the ThisClass, rather than an instance method.
So what you need is something like
tc.stub :ext_access_token, mock_client do
puts tc.get_access_token
end

Django rest auth with Allauth

I have implemented django rest auth with Allauth and its working fine if I login through google access_token but there is a case when some client device need to login by google id_token.
I am getting error if I use id_token instead of access_token
{
"non_field_errors": [
"Incorrect value"
]
}
please help me out
Update your files like
../allauth/socialaccount/providers/google/provider.py:
class GoogleProvider(OAuth2Provider):
....
def extract_uid(self, data):
try:
return str(data['id'])
except KeyError:
return str(data['user_id'])
../allauth/socialaccount/providers/google/views.py:
class GoogleOAuth2Adapter(OAuth2Adapter):
provider_id = GoogleProvider.id
access_token_url = 'https://accounts.google.com/o/oauth2/token'
authorize_url = 'https://accounts.google.com/o/oauth2/auth'
profile_url = 'https://www.googleapis.com/oauth2/v1/userinfo'
token_url = 'https://www.googleapis.com/oauth2/v1/tokeninfo'
def complete_login(self, request, app, token, **kwargs):
if 'rest-auth/google' in request.path:
print('rest-auth api')
# /api/rest-auth/google
# but not for website login with google
resp = requests.get(self.token_url,
params={'id_token': token.token,
'alt': 'json'})
else:
print('else else rest-auth api')
resp = requests.get(self.profile_url,
params={'access_token': token.token,
'alt': 'json'})
resp.raise_for_status()
extra_data = resp.json()
login = self.get_provider() \
.sociallogin_from_response(request,
extra_data)
return login
oauth2_login = OAuth2LoginView.adapter_view(GoogleOAuth2Adapter)
oauth2_callback = OAuth2CallbackView.adapter_view(GoogleOAuth2Adapter)
For using id_token you will get only these fileds (access_type, audience, email, email_verified, expires_in, issued_at, issued_to, issuer, nonce, scope, user_id, verified_email). So if your user table required phone and name you can set the to empty name='' etc. For this you can use the following code.
Set user model required fields to empty for covering id_token case
It depends upon your user model, in my case we need both phone and name so I have set them empty. If you don't do this you will get failed constraints errors.
../allauth/socialaccount/providers/base.py
class Provider(object):
def sociallogin_from_response(self, request, response):
....
common_fields = self.extract_common_fields(response)
common_fields['name'] = common_fields.get('name', '')
common_fields['phone'] = common_fields.get('phone', '')
common_fields['username'] = uid
....
I have set the username to user id obtained from social platform api. Later I am forcing user to update its details (username, name, phone etc).

Storing emails in sent items of Outlook using add in

I am trying to develop an add in for Outlook in Visual Studio under .net framework 4.0. I used smtp protocol for sending an email from my Outlook addin. I am not able to find the sent mail in sent folder of Outlook.
How do I store sent mail in the sent folder of Outlook?
Till now I have written this code for sending mail.
public bool SendEMail(){
MailMessage mailNew = new MailMessage();
var smtp = new SmtpClient("SmtpServer")
{
EnableSsl = false,
DeliveryMethod = SmtpDeliveryMethod.Network
};
smtp.Port = 587;
smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
smtp.UseDefaultCredentials = false;
System.Net.NetworkCredential credentials = new System.Net.NetworkCredential("UserName", "password");
smtp.EnableSsl = false;
smtp.Credentials = credentials;
MailAddress mailFrom = new MailAddress("clark#gmail.com");
mailNew.From = mailFrom;
mailNew.To.Add("someone#gmail.com");
mailNew.Subject = Subject;
mailNew.IsBodyHtml = Html;
mailNew.Body = Body;
smtp.Send(mailNew);
return true;
}
I want to add coding for storing the sent mail in sent folder of Outlook.
You will need to create a fake sent item. Note that messages in the Outlook Object Model are created in the unsent state, which cannot be modified.
The only exception is the post item. The following VB script creates a poat item in the Sent Item folder, resets the message class, reopens it as a regular MailItem (which is now in the sent state). Note that you cannot set the sender related properties using OOM alone and you cannot set the sent/received dates.
'create PostItem
set msg = Application.Session.GetDefaultFolder(olFolderSentMail).Items.Add("IPM.Post")
msg.MessageClass = "IPM.Note"
msg.Subject = "fake sent email"
msg.Body = "test"
msg.Save
vEntryId = msg.EntryID
set msg = Nothing 'release the mesage
'and reopen it as MailItem
set msg = Application.Session.GetItemFromID(vEntryId)
'make sure PR_ICON_INDEX is right
msg.PropertyAccessor.SetProperty "http://schemas.microsoft.com/mapi/proptag/0x10800003", -1
set vRecip = msg.Recipients.Add("fakeuser#domain.demo")
vRecip.Resolve
msg.Save
If using Redemption is an option, it lets you set the sent state before the first save (MAPI limitation) and allows to set the sender and date properties correctly:
set Session = CreateObject("Redemption.RDOSession")
Session.MAPIOBJECT = Application.Session.MAPIOBJECT
set msg = Session.GetDefaultFolder(olFolderSentMail).Items.Add("IPM.Note")
msg.Sent = true
msg.Subject = "fake sent email"
msg.Body = "test"
set vRecip = msg.Recipients.Add("fakeuser#domain.demo")
vRecip.Resolve
'dates
msg.SentOn = Now
msg.ReceivedTime = Now
'create fake sender
vSenderEntryID = Session.AddressBook.CreateOneOffEntryID("the sender", "SMTP", "me#domain.demo", true, true)
set vSender = Session.AddressBook.GetAddressEntryFromID(vSenderEntryID)
msg.Sender = vSender
msg.SentOnBehalfOf = vSender
msg.Save

How to export a Confluence "Space" to PDF using remote API

How can I export a Confluence 'space' as a pdf? It looks like it might still be supported in Confluence 5.0 using the XML-RPC API. I cannot find an example of what to call, though.
https://developer.atlassian.com/display/CONFDEV/Remote+API+Specification+for+PDF+Export#RemoteAPISpecificationforPDFExport-XML-RPCInformation
That link says calls should be prefixed with pdfexport, but then doesn't list any of the calls or give an example.
This works using Bob Swift's SOAP library ('org.swift.common:confluence-soap:5.4.1'). I'm using this in a gradle plugin, so you'll need to change a few things
void exportSpaceAsPdf(spaceKey, File outputFile) {
// Setup Pdf Export Service
PdfExportRpcServiceLocator serviceLocator = new PdfExportRpcServiceLocator()
serviceLocator.setpdfexportEndpointAddress("${url}/rpc/soap-axis/pdfexport")
serviceLocator.setMaintainSession(true)
def pdfService = serviceLocator.getpdfexport()
// Login
def token = pdfService.login(user, password)
// Perform Export
def pdfUrl = pdfService.exportSpace(token, spaceKey)
// Download Pdf
HttpClient client = new DefaultHttpClient();
HttpGet httpget = new HttpGet(pdfUrl)
httpget.addHeader(
BasicScheme.authenticate(
new UsernamePasswordCredentials(user,password),"UTF-8", false))
HttpResponse response = client.execute(httpget)
HttpEntity entity = response.getEntity()
if (entity != null) {
InputStream inputStream = entity.getContent()
FileOutputStream fos = new FileOutputStream(outputFile)
int inByte
while ((inByte = inputStream.read()) != -1)
fos.write(inByte)
inputStream.close()
fos.close()
} else {
throw new GradleException("""Cannot Export Space to PDF:
Space: ${spaceKey}
Dest: ${outputFile.absolutePath}
URL: ${pdfUrl}
Status: ${response.getStatusLine()}
""")
}
}
I know this is a PHP example, not Ruby, but you can check out the XML-RPC example in VoycerAG's PHP project on Github at https://github.com/VoycerAG/confluence-xmlrpc-pdf-export/blob/master/src/Voycer/Confluence/Command/PdfExportCommand.php ... hope it helps.
Basically you just need to make a call to the login method and user the authentication token returned to make a call to the exportSpace method. That in turn gives you back a URL which an authenticated user can then download the PDF from.
Turns out the soap API is the only currently available api for exporting a space
Using the Savon library in Ruby here:
require 'savon'
# create a client for the service
# http://<confluence-install>/rpc/soap-axis/pdfexport?wsdll
client = Savon.client(wsdl: 'https://example.atlassian.net/wiki/rpc/soap-axis/pdfexport?wsdl', read_timeout: 200)
# call the 'findUser' operation
response = client.call(:login, message: {username: "user", password: "pass"})
token = response.body[:login_response][:login_return]
response = client.call(:export_space, message:{token: token, space_key: "SPACE KEY"})

Creating a single page proxy using Ruby Sinatra

I am trying to use Ruby Sinatra to create a simple proxy for a specific web page. I can do it in C#, I just can't seem to work it out for Sinatra, the C# code is below:
<%# WebHandler Language="C#" Class="Map" %>
using System;
using System.Web;
using System.Net;
using System.IO;
public class Map : IHttpHandler {
static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[0x1000];
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
output.Write(buffer, 0, read);
}
public void ProcessRequest(HttpContext context)
{
string gmapUri = string.Format("http://maps.google.com/maps/api/staticmap{0}", context.Request.Url.Query);
WebRequest request = WebRequest.Create(gmapUri);
using (WebResponse response = request.GetResponse())
{
context.Response.ContentType = response.ContentType;
Stream responseStream = response.GetResponseStream();
CopyStream(responseStream, context.Response.OutputStream);
}
}
public bool IsReusable {
get {
return false;
}
}
}
The Ruby Sinatra code I have tried is as follows:
require 'rubygems'
require 'sinatra'
get '/mapsproxy/staticmap' do
request.path_info = 'http://maps.google.com/maps/api/staticmap'
pass
end
I am assuming that the Sinatra one does not work (get a 404) as is is only passing the request to pages in the same domain. Any hep would be greatly appreciated.
EDIT:
With the Tin Man's help I've come up with a nice succinct solution, which works well for me:
get '/proxy/path' do
URI.parse(<URI> + request.query_string.gsub("|", "%7C")).read
end
Thanks for all the help.
If you want your Sinatra app to retrieve the URL, you'll need to fire up a HTTP client of some sort:
get '/mapsproxy/staticmap' do
require 'open-uri'
open('http://maps.google.com/maps/api/staticmap').read
end
I think this will work and is about as minimal as you can get.
You could use HTTPClient if you need more tweakability.
Also, I think that Rack can do it. Sinatra is built on top of Rack, but it's been a while since I played at that level.
I still need to find a way to extract the contentType from the response
From the Open-URI docs:
The opened file has several methods for meta information as follows since
it is extended by OpenURI::Meta.
open("http://www.ruby-lang.org/en") {|f|
f.each_line {|line| p line}
p f.base_uri # <URI::HTTP:0x40e6ef2 URL:http://www.ruby-lang.org/en/>
p f.content_type # "text/html"
p f.charset # "iso-8859-1"
p f.content_encoding # []
p f.last_modified # Thu Dec 05 02:45:02 UTC 2002
}
For your purposes something like this should work:
content_type = ''
body = open("http://www.ruby-lang.org/en") {|f|
content_type = f.content_type # "text/html"
f.read
}
I haven't tested that, but I think the return value of the block will be assigned to body. If that doesn't work then try:
content_type = ''
body = ''
open("http://www.ruby-lang.org/en") {|f|
content_type = f.content_type # "text/html"
body = f.read
}
but I think the first will work.
With the help of the Tin Man and TK-421 I've worked out a solution, see the Sinatra route below:
get '/proxy/path' do
require 'open-uri'
uri = URI.parse(<URI>)
getresult = uri.read
halt 200, {'Content-Type' => getresult.content_type}, getresult
end
Just replace the <URI> with the page you require, and you're good to go.
After some more playing this is what I've come up with:
get '/proxy/path' do
URI.parse(<URI> + request.query_string.gsub("|", "%7C")).read
end
As mentioned else where you need to require 'open-uri' at the top of the code. The reason for the gsub is that for some reason the parse fails if they are left in, and my browser doesn't encode them automatically.

Resources