Create file/folder on Shared drive via service account - google-drive-api

I'm using a G-Suite Google Drive and Service account to connect to a Shared Drive. I'm using the PHP API library. I have previously made this work with the "regular" Google drive but we are moving to shared drive (aka Team Drive)
I can use files->listFiles() to get the file list, using:
$options = array('pageSize' => 100,
'corpora' => 'drive',
'supportsTeamDrives' => true,
'includeTeamDriveItems' => true,
'teamDriveId' => $sharedID,
'fields' => "nextPageToken, files(id, name)",
'q' => "'" . $pParentFolderID . "' in parents "
. " and name = \"" . $pFolderName . "\" "
. " and mimeType = 'application/vnd.google-apps.folder' "
. " and not trashed"
);
try{
$files_list = $this->drive_service->files->listFiles($optParams);
This works and gives me the ID for the specific file/folder I ask for.
However, attempting to create a folder in the top folder on the drive results in 404 error, saying that the file/folder is not found, even though I have just retrieved the correct ID from it.
$param =array( 'supportsAllDrives' => true,
'supportsTeamDrives' => true,
'teamDriveId' => $SharedID,
'parents' => array($pParentFolderID),
'name' => $pFolderName,
'mimeType' => 'application/vnd.google-apps.folder');
$fileMetadata = new Google_Service_Drive_DriveFile($param);
try {
$folderObj = $this->drive_service->files->create($fileMetadata, array('fields' => 'id'));
I have tried all kinds of permutations of this, but always get the 404. I have verified many times that the file ID for the parent is correct. I have tried using teamdriveid, driveid and various other options.
This is the data that I send and the data I get back from Google:
array(6) {
["supportsAllDrives"]=>
bool(true)
["supportsTeamDrives"]=>
bool(true)
["teamDriveId"]=>
string(19) "0ALay-iFeEOX6Uk9PVA"
["parents"]=>
array(1) {
[0]=>
string(33) "1oI72fkTb-AObYWBEOI-ykS5eDYg3L2ar"
}
["name"]=>
string(9) "FieldTest"
["mimeType"]=>
string(34) "application/vnd.google-apps.folder"
}
Trying to create:
Error from Google:array(1) {
["error"]=>
array(3) {
["errors"]=>
array(1) {
[0]=>
array(5) {
["domain"]=>
string(6) "global"
["reason"]=>
string(8) "notFound"
["message"]=>
string(50) "File not found: 1oI72fkTb-AObYWBEOI-ykS5eDYg3L2ar."
["locationType"]=>
string(9) "parameter"
["location"]=>
string(6) "fileId"
}
}
["code"]=>
int(404)
["message"]=>
string(50) "File not found: 1oI72fkTb-AObYWBEOI-ykS5eDYg3L2ar."
}
}
This process works with the "regular" drive, but fails on the Shared Drive.
Anyone have an idea what is missing?

You are providing supportsAllDrives in the request body, when you should be providing it as a query parameter, as specified here. Also, supportsTeamDrives and teamDriveId are not needed (and they are deprecated). So you should change this:
$param =array( 'supportsAllDrives' => true,
'supportsTeamDrives' => true,
'teamDriveId' => $SharedID,
'parents' => array($pParentFolderID),
'name' => $pFolderName,
'mimeType' => 'application/vnd.google-apps.folder');
To this:
$param =array( 'parents' => array($pParentFolderID),
'name' => $pFolderName,
'mimeType' => 'application/vnd.google-apps.folder');
Also, as I said, you should provide supportsAllDrives as a parameter when making the call. So you should change this:
$folderObj = $this->drive_service->files->create($fileMetadata, array('fields' => 'id'));
To this:
$folderObj = $this->drive_service->files->create($fileMetadata, array('fields' => 'id', 'supportsAllDrives' => true));
Because you are providing supportsAllDrives in the request body and not as a parameter, you cannot access shared drives.
I hope this is of any help.

Related

Class Swift_Transport_Esmtp_Auth_CramMd5Authenticator does not exist

I can't seem to send an email with laravel 5.4 on after setting the right configurations in config/mail.php. I'm using smtp driver here is summary of my files.
Here is the config/mail.php
<?php
return [
'driver'=>env('MAIL_DRIVER', 'smtp'),
'host'=>env('MAIL_HOST', 'smtp.gmail.com'),
'port' => env('MAIL_PORT', 587),
'from' => [
'address' => env('MAIL_FROM_ADDRESS', 'info#afecamworld.org'),
'name' => env('MAIL_FROM_NAME', 'National President'),
],
'encryption' => env('MAIL_ENCRYPTION', 'ssl'),
'username' => env('MAIL_USERNAME', 'my-gmail-email'),
'password' => env('MAIL_PASSWORD', 'my-gmail-password'),
'sendmail' => '/usr/sbin/sendmail -bs',
'markdown' => [
'theme' => 'default',
'paths' => [
resource_path('views/vendor/mail'),
],
],
This is the SendActivationEmail class
<?php
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class SendActivationEmail extends Notification {
use Queueable;
protected $token;
public function __construct($token) {
$this->token = $token;
}
public function via($notifiable){
return ['mail', 'database'];
}
public function toMail($notifiable) {
return (new MailMessage)->subject('Activation Your Account')->greeting('Hello!')->line('You need to activate your email before you can login.')->action('Activate Email', route('activate_account', ['token' => $this->token]))->line('Thank you for joining our Online Community!');
}
}
?>
This is the top part of the error
(1/1) ReflectionException
Class Swift_Transport_Esmtp_Auth_CramMd5Authenticator does not exist
in DependencyContainer.php (line 309)
I will be grateful for any help to resolve this error on dreamhost, thanks.
The best way to resolve this problem is to delete the files in the vendor folder and redo composer install and composer update, that's how I fixed my problem

Logstash - How to trigger Celery tasks through RabbitMQ

Can someone explain to me how I can trigger Celery tasks through Logstash?
Is it possible?
If I try to do that in PHP through the 'php-amqplib' library it works fine: (without using Logstash)
$connection = new AMQPStreamConnection(
'rabbitmq.local',
5672,
'guest',
'guest'
);
$channel = $connection->channel();
$channel->queue_declare(
'celery',
false,
true,
false,
false
);
$taskId = rand(1000, 10000);
$props = array(
'content_type' => 'application/json',
'content_encoding' => 'utf-8',
);
$body = array(
'task' => 'process_next_task',
'lang' => 'py',
'args' => array('ktest' => 'vtest'),
'kwargs' => array('ktest' => 'vtest'),
'origin' => '#'.'mytest',
'id' => $taskId,
);
$msg = new AMQPMessage(json_encode($body), $props);
$channel->basic_publish($msg, 'celery', 'celery');
According to the Celery docs:
http://docs.celeryproject.org/en/latest/internals/protocol.html
I'm trying to send the request in the json format, this is my Logstash filter:
ruby
{
remove_field => ['headers', '#timestamp', '#version', 'host', 'type']
code => "
event.set('properties',
{
:content_type => 'application/json',
:content_encoding => 'utf-8'
})
"
}
And Celery answer is:
[2017-05-05 14:35:09,090: WARNING/MainProcess] Received and deleted unknown message. Wrong destination?!
{content_type:None content_encoding:None delivery_info:{'exchange': 'celery', 'routing_key': 'celery', 'redelivered': False, 'consumer_tag': 'None4', 'delivery_tag': 66} headers={}}
Basically, Celery is not able to decode my message format or better... I'm not able to set the request in the JSON format :)
It's driving me crazy, thank you in advance for any clues :)
Forgot it, this is my output plugin in Logstash
rabbitmq
{
key => "celery"
exchange => "celery"
exchange_type => "direct"
user => "${RABBITMQ_USER}"
password => "${RABBITMQ_PASSWORD}"
host => "${RABBITMQ_HOST}"
port => "${RABBITMQ_PORT}"
durable => true
persistent => true
codec => json
}
From the information provided in this question, you can't.
When you're playing with the event in the ruby filter, you're actually playing with what will be put in the body of the message, while you'd like to set the rabbitmq headers and properties of your message.
Till that functionality has been tackled, I do not think you'll be able to achieve it unless of course you implement it yourself. After all, the plugin is available on github.
As Olivier said, right now is not possible but I've created a pull request to the official project.
https://github.com/logstash-plugins/logstash-output-rabbitmq/pull/59
If you are looking for a working version take a look to my clone:
https://github.com/useless-stuff/logstash-output-rabbitmq
You should be seriously scared about that code :)
I'm completely far away to be a Ruby developer
But it works :)

Fatal error: Class 'mPDF' not found in myproject/vendor/kartik-v/yii2-mpdf/Pdf.php on line 281

I have used kartik pdf extension to print my report in pdf format.Things are going well in my local computer but when i put my codes in server error appears like this:
Fatal error: Class 'mPDF' not found in myproject/vendor/kartik-v/yii2-mpdf/Pdf.php on line 281
In server i have uploaded yii2-mpdf folder inside kartik-v folder and also mpdf folder.
My code of controller for pdf print:
use kartik\mpdf\Pdf;
public function actionPearlFinancialReport()
{
$pdf = new Pdf([
//'mode' => Pdf::MODE_CORE,
'mode' => Pdf::MODE_UTF8,
'format' => Pdf::FORMAT_A4,
'orientation' => Pdf::ORIENT_PORTRAIT,
'destination' => Pdf::DEST_BROWSER,
'content' => $this->renderPartial('_financial_report', ['model' => $model,'parameter'=>$parameter]),
'cssFile' => '#vendor/kartik-v/yii2-mpdf/assets/kv-mpdf-bootstrap.min.css',
'cssInline'=> '.kv-heading-1{font-size:15px;text-align:center;}',
'options' => ['title' => 'Pearl Financial Report'],
'methods' => [
'SetHeader'=>['Pearl Financial Report'],
'SetFooter'=>['{PAGENO}'],
]
]);
$response = Yii::$app->response;
$response->format = \yii\web\Response::FORMAT_RAW;
$headers = Yii::$app->response->headers;
$headers->add('Content-Type', 'application/pdf');
}
What to do?
Try this
'cssFile' => '#vendor/kartik-v/yii2-mpdf/src/assets/kv-mpdf-bootstrap.min.css',
Try to register this extension with composer:
For example my work directory is c:\xampp\htdocs\my-project
In a command prompt -> cd c:\xampp\htdocs\my-project
And register with this command:
C:\xampp\htdocs\my-project>php c:\xampp\htdocs\composer.phar require kartik-v/yii2-mpdf "dev-master"
I always register kartik's extensions with this metod, I hope want to be useful for you too.

How to parse this JSON object/string?

I am trying to parse the JSON written # http://a0.awsstatic.com/pricing/1/ec2/sles-od.min.js
Here is a quick snippet from above link:
{vers:0.01,config:{rate:"perhr",valueColumns:["vCPU","ECU","memoryGiB","storageGB","sles"],currencies:["USD"],regions:[{region:"us-east",instanceTypes:[{type:"generalCurrentGen",sizes:[{size:"t2.micro",vCPU:"1",ECU:"variable",
...
...
...
...
Please visit the aforementioned link to see the complete JSON.
As seen above, none of the keys of above JSON have Double Quotes around them.
This leads to malformed JSON string and my JSON parser is failing at it. I also tried putting this JSON in http://www.jsoneditoronline.org/ and it fails as well.
Now, this is the same link which is used by Amazon to display various prices of their EC2 instance. So I think I am missing something here. My Googling led me to believe that above thing is not JSON and is instead JSONP.. I don't understand what is that.
Could you help me understand how to parse this JSON. BTW, I am doing this work in perl using JSON Module.
Some background:
Amazon Web Services does not have an API to get Pricing info programmatically. Hence I am parsing these links which is what amazon is doing while displaying pricing information here. Besides, I am not from programming space and perl is all I know.
Like you said JSONP or "JSON with padding" can't be parsed by json parser because it is not json (it is a different format). But it is actually a json with the prefix (padding)
The padding is typically the name of a callback function that wraps json.
In this case, its default callback names 'callback' and we can do a bit hackiest way by using Regular Expression to capture json that is wrapped by 'callback()' like this
s/callback\((.*)\);$/$1/s;
Also, if you would like to use JSON library, you can enable allow_barekey which means you don't need those quotes around those keys.
Below is my working code. I use LWP::Simple to get the content for the given and Data::Dump to print the isolated data structure.
use strict;
use warnings;
use LWP::Simple;
use JSON;
my $jsonp = get("http://a0.awsstatic.com/pricing/1/ec2/sles-od.min.js")
or die "Couldn't get url";
( my $json = $jsonp ) =~ s/callback\((.*)\);$/$1/s; #grap the json from $jsonp and store in $json variable
my $hash = JSON->new->allow_barekey->decode ( $json );
use Data::Dump;
dd $hash;
Outputs:
{
config => {
currencies => ["USD"],
rate => "perhr",
regions => [
{
instanceTypes => [
{
sizes => [
{
ECU => "variable",
memoryGiB => 1,
size => "t2.micro",
storageGB => "ebsonly",
valueColumns => [{ name => "os", prices => { USD => 0.023 } }],
vCPU => 1,
},
{
ECU => "variable",
memoryGiB => 2,
size => "t2.small",
storageGB => "ebsonly",
valueColumns => [{ name => "os", prices => { USD => 0.056 } }],
vCPU => 1,
},
{
ECU => "variable",
memoryGiB => 4,
size => "t2.medium",
storageGB => "ebsonly",
valueColumns => [{ name => "os", prices => { USD => 0.152 } }],
vCPU => 2,
},
{
ECU => 3,
memoryGiB => 3.75,
size => "m3.medium",
storageGB => "1 x 4 SSD",
valueColumns => [{ name => "os", prices => { USD => "0.170" } }],
vCPU => 1,
},
....
As said in comments above, it is not JSON so it can't be parsed by JSON parser... But for an quick & (very)dirty work, you can try the JSON::DWIW module.
The next code:
use 5.014;
use warnings;
use WWW::Mechanize;
use Data::Dump;
use JSON::DWIW;
my $mech = WWW::Mechanize->new();
my $jsonstr = $mech->get('http://a0.awsstatic.com/pricing/1/ec2/sles-od.min.js')->content;
($jsonstr) = $jsonstr =~ /callback\((.*)\)/s;
my $json_obj = JSON::DWIW->new;
my $data = $json_obj->from_json( $jsonstr );
dd $data;
prints a structure what maybe is what you want, e.g.:
{
config => {
currencies => ["USD"],
rate => "perhr",
regions => [
{
instanceTypes => [
{
sizes => [
{
ECU => "variable",
memoryGiB => 1,
size => "t2.micro",
storageGB => "ebsonly",
valueColumns => [{ name => "os", prices => { USD => 0.023 } }],
vCPU => 1,
},
{

Vagrant - JSON Attribute Syntax/Use

I am currently using Vagrant to install a glassfish server via chef_solo cookbook. Everything installs correctly and I can access the server, but it requires that I enable secure_admin to access the server remotely from my host machine.
The problem lies in that I cannot seem to find, or understand the JSON syntax for Vagrant to properly modify the attribute for secure_admin to enable.
I am using this cookbook: https://github.com/realityforge/chef-glassfish
In the instructions it explains to modify such attributes to enter code such as this:
# Create a basic domain that logs to a central graylog server
glassfish_domain "my_domain" do
port 80
admin_port 8103
extra_libraries ['https://github.com/downloads/realityforge/gelf4j/gelf4j-0.9-all.jar']
logging_properties {
"handlers" => "java.util.logging.ConsoleHandler, gelf4j.logging.GelfHandler",
".level" => "INFO",
"java.util.logging.ConsoleHandler.level" => "INFO",
"gelf4j.logging.GelfHandler.level" => "ALL",
"gelf4j.logging.GelfHandler.host" => 'graylog.example.org',
"gelf4j.logging.GelfHandler.defaultFields" => '{"environment": "' + node.chef_environment + '", "facility": "MyDomain"}'
}
end
However, if I wish to modify features such as the port or domain name, I have to edit those attributes with this syntax (Whats in my vagrantfile already):
chef.json = {
"glassfish" => {
"base_dir" => "/usr/local/glassfish",
"domains_dir" => "/usr/local/glassfish/glassfish/domains",
"domains" => {
"domain1" => {
"config" => {
"domain_name" => "domain1",
"admin_port" => 4848,
"username" => "root",
"password" => "admin",
}
}
}
}
}
This code makes sense to me as I see within the recipe "attribute_driven_domain" in this cookbook, that the open statements are described as such. Meaning to edit the minimum memory of the domain, I would have type:
"glassfish" => {
"domains" => {
"domain1" => {
"config" => {
"min_memory" => 512
}
}
}
}
Which this ^ , corresponds to:
['glassfish']
['domains']
['config']
['min_memory']
....Found in this section of the recipe:
gf_sort(node['glassfish']['domains']).each_pair do |domain_key, definition|
domain_key = domain_key.to_s
Chef::Log.info "Defining GlassFish Domain #{domain_key}"
admin_port = definition['config']['admin_port']
username = definition['config']['username']
secure = definition['config']['secure']
password_file = username ? "#{node['glassfish']['domains_dir']}/#{domain_key}_admin_passwd" : nil
system_username = definition['config']['system_user']
system_group = definition['config']['system_group']
if (definition['config']['port'] && definition['config']['port'] < 1024) || (admin_port && admin_port < 1024)
include_recipe 'authbind'
end
glassfish_domain domain_key do
min_memory definition['config']['min_memory'] if definition['config']['min_memory']
max_memory definition['config']['max_memory'] if definition['config']['max_memory']
max_perm_size definition['config']['max_perm_size'] if definition['config']['max_perm_size']
max_stack_size definition['config']['max_stack_size'] if definition['config']['max_stack_size']
port definition['config']['port'] if definition['config']['port']
However, at the part that defines the secure admin, I can't see a distinct place that would indicate where it is supposed to be placed in the chef.json block. Found in this section:
glassfish_secure_admin "#{domain_key}: secure_admin" do
domain_name domain_key
admin_port admin_port if admin_port
username username if username
password_file password_file if password_file
secure secure if secure
system_user system_username if system_username
system_group system_group if system_group
action ('true' == definition['config']['remote_access'].to_s) ? :enable : :disable
end
I can't seem to figure out where the secure_admin attribute is suppose to placed in the chef.json block within my vagrantfile. I've tried placing it different spots, such as under the glassfish level, under the domains level, under the config.
I really don't know what I am exactly suppose to put, or where.
I have been using variants of this:
"secure_admin" => {
"domain_name" => "domain1"
"action" => :enable
}
or like this if it was under domain1 but above config:
"secure_admin" => {
"action" => :enable
}
Most of the time it doesn't give any feedback of change or error, sometimes if its put in certain spots it fails because it tries to read it as a separate domain, but other than that not much.
Is the syntax that I'm currently using to modify attributes incorrect? I'm pretty fresh with this stuff, so I don't really know. Sorry for the terribly long post.
It looks like to enable remote access you would set the node attribute for domain['config']['remote_access'] to true. This is just a guess based on the ternary operator. So in your original example:
"glassfish" => {
"base_dir" => "/usr/local/glassfish",
"domains_dir" => "/usr/local/glassfish/glassfish/domains",
"domains" => {
"domain1" => {
"config" => {
"domain_name" => "domain1",
"admin_port" => 4848,
"username" => "root",
"password" => "admin",
"remote_access" => true
}
}
}
}