Drupal 7 Services create node with images - drupal

I installed a new Drupal 7.56 distribution.
I want to create new nodes via java client.
However, After little googling I found the “Services” module for Drupal 7.
So I installed it, with the next module:
Services
Ctools (required for Services)
Libraries (required for Services)
OAuth 1.0
So, I installed these modules. From the Structure menu I created the Service.
Endpoint: API
Server: REST
I enabled the Session and OAuth authentication.
I created a new Content type.
name: TestContent (Machine name: testcontent)
Fields:
Title (M.n.: title)
Body (M.n.: body)
Pics (M.n: field_pics) (Type: Image) Number of values: 5
In this Service I enabled all resource (file, user, etc..)
I Disabled the OAuth, because I will set up it later.
Now, I opened my Postman client.
Logging in: admin/admin
{
"sessid": "QZTYSQu3-I9pacOpoSP--V_LkGcusy2grl12U_CyKrY",
"session_name": "SESS51ebf8732a20744576a234cf7af43040",
"token": "jkUDb6MsGMHt_mBlGbm02O-lyZq-2nRTqD1OslxtvAg",
"user": {
"uid": "6",
"name": "admin",
…
Now I have a token. Now I upload two picture.
http://test.dd:8083/api/file
Got these responses
{
"fid": "6",
"uri": "http://test.dd:8083/api/file/6"
}
{
"fid": “7”,
"uri": "http://test.dd:8083/api/file/7”
}
Ok, Now I’ll try to create a new TestContent, and connect these Images to the node.
Ok, The node is created. But the Images isn’t connected to the node. But I didn’t get error message.
Why? What’s wrong?
I tried:
[ {fid:6} , {fid:7}]
und: [ { fid: 6 }]
Please give me ideas. Thank you

I found the solution on the Drupal site.
Run these GIT difference!
diff --git a/resources/node_resource.inc b/resources/node_resource.inc
index 8f870b7..6669a1a 100644
--- a/resources/node_resource.inc
+++ b/resources/node_resource.inc
## -339,8 +339,9 ## function _node_resource_create($node) {
);
$stub_form = drupal_build_form($node_type . '_node_form', $stub_form_state);
$form_state['triggering_element'] = $stub_form['actions']['submit'];
+ $node = (object) array_merge((array) $stub_node, (array) $node);
- drupal_form_submit($node_type . '_node_form', $form_state, (object)$stub_node);
+ drupal_form_submit($node_type . '_node_form', $form_state, $node);
if ($errors = form_get_errors()) {
return services_error(implode(" ", $errors), 406, array('form_errors' => $errors));
## -423,6 +424,7 ## function _node_resource_update($nid, $node) {
$node_type = $node['type'];
node_object_prepare($old_node);
+ $old_node = (object) array_merge((array) $old_node, (array) $node);
// Setup form_state.
$form_state = array();
diff --git a/resources/user_resource.inc b/resources/user_resource.inc
index 304a293..c1f9b5a 100644
--- a/resources/user_resource.inc
+++ b/resources/user_resource.inc
## -471,6 +471,7 ## function _user_resource_update($uid, $account) {
return services_error(t('You are not allowed to change your username.'), 406);
}
+ $account_loaded = (object) array_merge((array) $account_loaded, (array) $account);
$form_state['values']['op'] = variable_get('services_user_save_button_resource_update', t('Save'));
$form_state['values']['#user_category'] = $category;
$form_state['values']['#account'] = $account_loaded;
See more: Here

Related

Nexus 3 | How to create (external) users using Nexus 3 APIs?

I'm trying to create external user on Nexus 3 using nexus 3 APIs. Following are the details:
Posting Groovy Script using: http://localhost:8081/nexus3/service/rest/v1/script
{
"name": "d8b3baeb-628a-43cc-9a9c-9a156f399e2",
"type": "groovy",
"content": "security.addUser('q018246a', '', '', '', true, 'd8b3baeb-628a-43cc-9a9c-9a156f399ae2', ['abc_test_role Developer Role']);"
}
Running Script using: http://localhost:8081/nexus3/service/rest/v1/script/d8b3baeb-628a-43cc-9a9c-9a156f399e2/run
Response:
{
"name": "d8b3baeb-628a-43cc-9a9c-9a156f399e2",
"result": "User{userId='q018246a', firstName='', lastName='', source='default'}"
}
Hitting though Postman, all working fine and users getting created. But through Application server it is giving Bad request.
Awkward behavior is, it's letting me create user using postman post script with blank first_name, last_name, email, password, but all these parameters are required on UI.
Another thing, It's showing source as default but how to I ensure source as LDAP?
I assume you're trying to map an LDAP user? If so, this will work:
import org.sonatype.nexus.security.role.RoleIdentifier;
import org.sonatype.nexus.security.user.User;
String userId = 'someuser';
String newRoleId = 'nx-admin'
User user = security.securitySystem.getUser(userId, 'LDAP')
if(user != null) {
RoleIdentifier newRole = new RoleIdentifier('default', newRoleId);
user.addRole(newRole)
security.securitySystem.setUsersRoles(user.getUserId(), 'LDAP', user.getRoles());
} else {
log.warn("No user with ID of $userId found.")
}

How to use Cloud Functions for Firebase to prerender pages for SEO?

The Cloud Functions for Firebase documentation here states that this can be done using cloud functions -
Prerendering for single page apps to improve SEO. This allows you to create dynamic meta tags for sharing across various social networks.
There are 2 questions I have:
Can someone explain with an example how pre-rendering is achieved?
How does this work in conjunction with Firebase Hosting? So let's say I have a webpage at xyz.com/salon/43 and in Firebase hosting I have a salon.html which is served in response to this request. Now in order to be able to prerender should I move from hosting to a cloud function which renders the webpage? In other words do I go from
"rewrites": [{
"source": "/salon/*",
"destination": "/salon.html"}]
to
"rewrites": [{
"source": "/salon", "function": "salon"}]
Two tasks:
- Add the function to your hosting rewrite as in your example
- Write the function to generate an html page
This tutorial provides a great example, with the following function as an example from a longer snippet:
const admin = require('firebase-admin');
function buildHtmlWithPost (post) {
const string = '<!DOCTYPE html><head>' \
'<title>' + post.title + ' | Example Website</title>' \
'<meta property="og:title" content="' + post.title + '">' \
'<meta property="twitter:title" content="' + post.title + '">' \
'<link rel="icon" href="https://example.com/favicon.png">' \
'</head><body>' \
'<script>window.location="https://example.com/?post=' + post.id + '";</script>' \
'</body></html>';
return string;
}
module.exports = function(req, res) {
const path = req.path.split('/');
const postId = path[2];
admin.database().ref('/posts').child(postId).once('value').then(snapshot => {
const post = snapshot.val();
post.id = snapshot.key;
const htmlString = buildHtmlWithPost(post);
res.status(200).end(htmlString);
});
};
First of all, sorry for my poor English.
After searching through Deep Web (joking), I found the solution. And the coolest solution was that I was able to integrate my Pioneer Ionic application with Firebase Hosting using Cloud Functions.
After reading the following topic:
https://github.com/firebase/firebase-tools/issues/33
The #TheRoccoB user explains how to host the static Web application in Firebase Hosting and redirect traffic from a URL to Cloud Functions.
What I did was map the routes that I have to index as:
{
"source": "/ shop / **",
    "function": "ssr"
},
{
"source": "/ * / promotions / **",
    "function": "ssr"
}
Since "ssr" is the name of my function in Cloud Functions. So I used the library https://github.com/prerender/prerender-node to check if the request is from a google crowler, in case I redirect the request to a https://github.com/prerender/prerender server.
const prerender = express ();
prerender.use (cors);
prerender.use (
    require ('prerender-node')
    // .set ('prerenderServiceUrl', 'http: // localhost: 3000')
    .set ('prerenderToken', '** TOKEN **')
);
prerender.use (require ('prerender-node'). set ('beforeRender', function (req, done) {
    // do you need to do?
    console.log ('Rendering URL:', req.path);
done ();
}));
prerender.use (require ('prerender-node') set ('afterRender', function (err, req, prerender_res) {
    // do you need to do?
    console.log (req.path + 'rendering completed!');
    console.log ('Errors:', err);
}));
prerender.get ('*', (req, res) => {
    console.log ('Calling function for URL:', req.path);
    res.set ('Cache-Control', 'public, max-age = 300, s-maxage = 600');
    res.status (200) .send (fs.readFileSync ('./ www / index.html'). toString ());
});
exports.ssr = functions.https.onRequest (prerender);
You are correct, you effectively rewrite your app's HTML page to point to a function instead of a static document. Then, when that page is accessed, your function will effectively generate the HTML that gets sent back to the browser. You are taking this opportunity to decide, at that very moment, what the contents of the HTML should be.
If the contents don't need to be generated on every single access (each of which costs money according to the billing rates shown on the pricing page), you'll also probably want to make use of caching to eliminate to serve cached, pre-rendered content from the Firebase Hosting CDNs.

Unit testing Symfony application using FOSElasticaBundle without an ES Server?

I have an application with an existing set of unit tests which are using SQLite as the DB. I have recently added search capabilities via ES which have replaced many of the endpoint actions that used to query the DB directly. I want to test all of the business logic involved with these endpoints without testing ES itself, which means no ES server available. I plan to test ES itself in a set of integration tests to be run less frequently.
My problem is trying to track down exactly what is going on with the execution flow.
My first inclination was to simply create a mock object of the ES Finder that FOSElasticaBundle creates for my index. Because I'm using pagination, it turned out to be more complex than I thought:
// code context: test method in unit test extending Symfony's WebTestCase
$client = $this->getClient();
$expectedHitCount = 10;
// Setup real objects which (as far as I can tell) don't act upon the ES client
// and instead only hold / manipulate the data.
$responseString = file_get_contents(static::SEARCH_RESULT_FILE_RESOURCE);
$query = SearchRepository::getProximitySearchQuery($lat, $lng, $radius, $offset, $limit);
$response = new Response($responseString, 200);
$resultSet = new RawPartialResults(new ResultSet($response, $query ));
// Create a mock pagination adapter which is what my service expects to be returned from
// the search repository.
$adapter = $this->getMockBuilder('FOS\ElasticaBundle\Paginator\RawPaginatorAdapter')
->disableOriginalConstructor()
->getMock();
$adapter->method('getTotalHits')->will($this->returnValue($expectedTotalCount));
$adapter->method('getResults')->will($this->returnValue($resultSet));
$adapter->method('getQuery')->will($this->returnValue($query));
$es = $this->getMockBuilder(get_class($client->getContainer()->get(static::ES_FINDER_SERVICE)))
->disableOriginalConstructor()
->getMock();
$es->method('createPaginatorAdapter')->will($this->returnValue($adapter));
// Replace the client container's service definition with our mock object
$client->getContainer()->set(static::ES_FINDER_SERVICE, $es);
This actually works all the way until I return the view from my controller. My service gets back the mock paginatior adapter with the pre-popuated result set from the JSON search response I have stored in a file (and subsequently passed into my ResultSet object). However, once I return the view, there seems to be a listener involved that tries to query ES again with the Query instead of using the ResultSet I already passed in.
I can't seem to find this listener. I also don't understand why it would try to query when a ResuletSet already exists.
I am using FOSRestBundle, as well, and making use of their ViewListener to auto-serialize whatever I return. I don't see any suspects in that flow, either. I think it may have something to do with the serialization of the result set, but so far haven't been able to track the offending code down.
Has anyone tried to do something similar to this before and have any suggestions on either how to debug my current setup or an alternative, better setup for mocking ES for this type of test?
After digging around I found an alternative solution that does not involve using mock objects. I am going to leave this open for the time being in case someone has a better approach, but the approach I decided to take in the mean time is to override the Client in my test environment.
FOSElasticaBundle has an example for overriding the client here: https://github.com/FriendsOfSymfony/FOSElasticaBundle/blob/master/Resources/doc/cookbook/suppress-server-errors.md
I was able to override the client in such a way that I could create a unique key from the request and then provide responses based on that key, essentially stubbing the server for all known requests. For requests that don't match I return a default empty response. This works well enough for me.
Client Code
<?php
namespace Acme\DemoBundle\Tests\Elastica;
use Elastica\Request;
use Elastica\Response;
use FOS\ElasticaBundle\Client as BaseClient;
class Client extends BaseClient
{
/**
* This array translates a key which is the md5 hash of the Request::toString() into
* a human friendly name so that we can load the proper response from a file in the
* file system.
*
* #var array
*/
protected $responseLookup = array(
'7fea3dda860a424aa974b44f508b6678' => 'proximity-search-response.json'
);
/**
* {#inheritdoc}
*/
public function request($path, $method = Request::GET, $data = array(), array $query = array())
{
$request = new Request($path, $method, $data, $query);
$requestKey = md5($request->toString());
$this->_log($request);
$this->_log("Test request lookup key: $requestKey");
if (!isset($this->responseLookup[$requestKey])
|| !$response = file_get_contents(__DIR__ . "/../DataFixtures/Resources/search/{$this->responseLookup[$requestKey]}")) {
return $this->getNullResponse();
}
return new Response($response);
}
public function getNullResponse()
{
$this->_log("Returning NULL response");
return new Response('{"took":0,"timed_out":false,"hits":{"total":0,"max_score":0,"hits":[]}}');
}
}
Configuration Change
// file: config_test.yml
parameters:
fos_elastica.client.class: Acme\DemoBundle\Tests\Elastica\Client
Sample Response File (proximity-search-response.json)
{
"took": 7,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 1,
"max_score": null,
"hits": [
{
"_index": "search",
"_type": "place",
"_id": "1",
"_score": null,
"_source": {
"location": "40.849100,-73.644800",
"id": 1,
"name": "My Place"
},
"sort": [
322.52855474383045
]
}
]
}
}
This solution works well and is fast, but the maintenance is a pain. If anything about the request changes, you need to retrieve the new request key from the log, update it in the array, and update the file with the new response data for the new request. I generally just curl the server directly and modify it from there.
I would love to see any other solutions that may be simpler, but I hope this helps someone else in the meantime!
you can try to disable the event listeners in your config_test.yml (or whatever is your test environment name).
fos_elastica:
indexes:
your_index_name:
types:
your_type_name:
persistence:
listener:
insert: false
update: false
delete: false

Redirect user to regional language site version by knowing the ip of users Drupal 7

We are basically developing a Drupal 7 site with multiple language support.
Users should be redirected to regional translated pages basing on their IP.
I have tried using the following modules, but they didn't help to achieve what I wanted.
Internalization
IP to Locale
How can I redirect users to a specific page basing on their IP?
I have added a module for the same... just adding the code. With little modifications it can be configured for any no of languages and options.
I am using APIs from http://ipinfodb.com/.
ip2locationlite.class.php -> file can be downloaded from this link "http://ipinfodb.com/ip_location_api.php". The file consists of a very simple class, just used for calling webservice provided by http://ipinfodb.com/ and can be avoided by using your own class with file_get_contents.
I used for only chinese.
/** Author : Sunny Jhunjhunwala (sunny.jhunjhunwala#sourcen.com)
* #file - the file basically uses the php api provided by ipinfodb to get user's country
*/
/**
* Implements hook_init().
* Only for the first time checks if user is from china or not, if yes then redirect user to chinese version of the site.
*/
function dw_ip2location_init() {
if (!(array_key_exists('visited', $_COOKIE)) && empty($GLOBALS['user']->uid)) {
// Set the cookie to check if the user is new or existing.
setcookie("visited", 1, time() + (10 * 365 * 24 * 60 * 60));
include_once ('ip2locationlite.class.php');
$ipLite = new ip2location_lite;
$ipLite->setKey('a00740f71ae6ed8db250cb4c3a8ecdac672b5eae4d2a28c06284aa5461d0636d');
// #TODO : remove the below if-else while moving to production.
if (isset($_GET['ip2location'])) {
$locations = $ipLite->getCountry($_GET['ip2location']);
} else {
$locations = $ipLite->getCountry($_SERVER['REMOTE_ADDR']);
}
if (!empty($locations) && is_array($locations)) {
// Checking if the user if from china and redirecting.
if ($locations['countryCode'] == 'CN' || $locations['countryName'] == 'china') {
$path = $_GET['q'];
$translations = i18n_get_path_translations($path);
$language = i18n_language_interface();
if($language->prefix != 'cn' ) {
global $base_url;
if(!drupal_is_front_page() && array_key_exists('zh-hans', $translations)) {
drupal_goto( $base_url . '/cn/' . $translations['zh-hans']['href'], array('absolute' => true));
}
else {
drupal_goto( $base_url . '/cn/', array('absolute' => true));
}
}
}
}
}
}

Getting an open graph action approved - change publish_stream to publish_action

UPDATED CODE:
I have an open graph action pending approval. I received a message back from Facebook saying this:
Your code is currently configured to publish a stream story. You must change your code so that when the test user triggers the action it produces an open graph story. Please make the appropriate changes and resubmit.
I followed all the tutorials regarding publishing actions and my tests all published successfully to my app timeline. The problem is that my app (which is a page tab) is already up and running - so I want to update it and add these new actions.
Are Facebook looking at the code in my current page tab - which is using the fmbl posttofeed share button - or are they looking at the tests I carried out with the new action? Is anyone able to shed some light on this?
This is the code I have in my test page that I used to publish the actions:
function postShare()
{
FB.api(
'/me/namespace:share',
'post',
{ photo: 'https://domain.com' },
function(response) {
if (!response || response.error) {
alert('Error occurred : ' + response.error);
} else {
alert('Share was successful! Action ID: ' + response.id);
}
});
}
// Load the SDK Asynchronously
(function(d){
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) {return;}
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
ref.parentNode.insertBefore(js, ref);
}(document));
// Init the SDK upon load
window.fbAsyncInit = function() {
FB.init({
appId : 'APP ID', // App ID
channelUrl : '//channel url', // Path to your Channel File
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true // parse XFBML
});
// listen for and handle auth.statusChange events
FB.Event.subscribe('auth.statusChange', function(response) {
if (response.authResponse) {
// user has auth'd your app and is logged into Facebook
FB.api('/me', function(me){
if (me.name) {
document.getElementById('auth-displayname').innerHTML = me.name;
}
})
document.getElementById('auth-loggedout').style.display = 'none';
document.getElementById('auth-loggedin').style.display = 'block';
} else {
// user has not auth'd your app, or is not logged into Facebook
document.getElementById('auth-loggedout').style.display = 'block';
document.getElementById('auth-loggedin').style.display = 'none';
}
});
// respond to clicks on the login and logout links
document.getElementById('auth-loginlink').addEventListener('click', function(){
FB.login();
});
document.getElementById('auth-logoutlink').addEventListener('click', function(){
FB.logout();
});
}
function loginUser() {
FB.login(function(response) { }, {scope:'publish_actions, email'});
}
I can't see how this is configured to publish a stream story and not an open graph story? Can anyone help with this is it's driving me insane and can't find anything out there to suggest what I'm doing is not publishing an action.
If, however when they are reviewing my actions they are looking at the code in my live app then of course it is not set up to trigger any open graph stories - as they haven't been approved yet!
Any help would be hugely appreciated.
Many thanks
Your question isn't entirely clear, but both the publish_actions and publish_stream Permissions both allow you to post Open Graph actions. The publish_stream permission however covers many other publishing types and is also optional, and if users remove that permission you won't be able to post OG actions for those users.
Update your authentication code to request publish_actions instead / as well
Finally got it working. Steps:
1. Added "Publish_action" Permission
2. Tested on FB Graph API Explorer successfully
3. Modified my Javascript (similar code as the postShare() method above)
FB.api('/me/namespace:purchase',
'post',
{ product: 'samples.ogp.me/367683346642550'; },
function(response) {
if (!response || response.error) {
alert('Error occured'+response.error);
} else {
alert('Post was successful! Action ID: ' + response.id);
}
});
The Facebook testers need the actual code running at your production server. They are going to use a Facebook test user to execute all the steps you described when you submitted the action. They won't use the already published stories. They will probably use the "Open Graph Test User".
You have two options here:
Try to publish the action with every user and if it doesn't work, publish the stream (so that the test user get the action published but your real user publish using the old code)
--- OR ---
Identify if the user is a test user (by recording the test users ids) and serve him the new code.
Anyway, the real action flow must be executable on the production server.
Basically you cannot post something to an album or any other kind of post when you are using an open graph story. For example the following is not allowed:
$data = $facebook->api('/me/photos', 'post', $args);//disallowed
$facebook->api(
'me/invig-test:share',
'POST',
array(
'app_id' => $configParam['appId'],
'type' => "test:photo",
'photo' => "http://samples.ogp.me/574859819237737",
'title' => "a photo",
'image[0][url]'=>"http://www.testapp.com/".$imgFile,
'image[0][user_generated]'=>'true',
'message' => $comments,
'fb:explicitly_shared'=>true,
)
);
Instead only do the "share":
$facebook->api(
'me/invig-test:share',
'POST',
array(
'app_id' => $configParam['appId'],
'type' => "test:photo",
'photo' => "http://samples.ogp.me/574859819237737",
'title' => "a photo",
'image[0][url]'=>"http://www.testapp.com/".$imgFile,
'image[0][user_generated]'=>'true',
'message' => $comments,
'fb:explicitly_shared'=>true,
)
);

Resources