View source
<?php
namespace Drupal\blogapi;
use Drupal\taxonomy\Entity\Term;
use Drupal\Core\Url;
use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Entity\EntityFieldManager;
use Drupal\Core\Extension\ModuleHandler;
use Drupal\Core\Config\ConfigFactory;
class BlogapiCommunicator {
const BLOGAPI_XML_ERROR_AUTH = 1;
const BLOGAPI_XML_ERROR_NODE_NOT_FOUND = 2;
const BLOGAPI_XML_ERROR_NODE_ACCESS = 3;
const BLOGAPI_XML_ERROR_NODE_UPDATE = 4;
const BLOGAPI_XML_ERROR_CT = 5;
const BLOGAPI_XML_ERROR_NODE_CREATE = 6;
const BLOGAPI_XML_ERROR_NODE_DELETE = 7;
const BLOGAPI_XML_ERROR_IMG_SIZE = 8;
const BLOGAPI_XML_ERROR_IMG_SAVE = 9;
public $entityTypeManager;
public $entityFieldManager;
public $pluginManager;
public $moduleManager;
public $blogapiConfig;
public function __construct(EntityTypeManager $entityTypeManager, EntityFieldManager $entityFieldManager, BlogapiProviderManager $blogapiProviderManager, ModuleHandler $moduleHandler, ConfigFactory $configFactory) {
$this->entityTypeManager = $entityTypeManager;
$this->entityFieldManager = $entityFieldManager;
$this->pluginManager = $blogapiProviderManager;
$this->moduleManager = $moduleHandler;
$this->blogapiConfig = $configFactory
->get('blogapi.settings');
}
public function getMethodImplementations() {
$plugins = $this->pluginManager
->getDefinitions();
$implementations = array();
foreach ($plugins as $plugin) {
$value = $this->pluginManager
->invoke($plugin['provider'], 'xmlrpc');
if (isset($value[0])) {
$implementations[] = $value[0];
}
}
return $implementations;
}
public function authenticate($user, $pass, $return_object = FALSE) {
$auth = \Drupal::service('user.auth');
if ($auth
->authenticate($user, $pass)) {
$user_load = user_load_by_name($user);
if ($return_object) {
return $user_load;
}
$id = $user_load
->id();
return (int) $id;
}
return FALSE;
}
public function validateBlogId($ct) {
$content_types = $this->blogapiConfig
->get('content_types');
if (in_array($ct, $content_types)) {
return TRUE;
}
return FALSE;
}
public function getNodeCategories($nid, $user, $pass) {
$user = $this
->authenticate($user, $pass, TRUE);
if (!$user) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_AUTH);
}
$node = $this->entityTypeManager
->getStorage('node')
->load($nid);
if (!$node) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_NODE_NOT_FOUND, $nid);
}
if (!$node
->access('view', $user)) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_NODE_ACCESS, $nid);
}
$ct = $node
->getType();
$taxonomy_fields = $this->blogapiConfig
->get('taxonomy_' . $ct);
$taxonomy_terms = $this
->getTaxonomyTerms($node, [
$taxonomy_fields,
]);
return $taxonomy_terms;
}
public function getTaxonomyFields($node) {
$taxonomy_fields = [];
$fields = $node
->getFieldDefinitions();
foreach ($fields as $i => $field) {
if ($this
->fieldIsTaxonomy($field)) {
$taxonomy_fields[] = $i;
}
}
return $taxonomy_fields;
}
public function fieldIsTaxonomy($field) {
$type = $field
->getType();
$handler = $field
->getSetting('handler');
if ($handler == 'default:taxonomy_term' && $type == 'entity_reference') {
return TRUE;
}
return FALSE;
}
public function getTaxonomyTerms($node, $taxonomy_fields) {
$terms = [];
if (is_array($taxonomy_fields) && !empty($taxonomy_fields)) {
foreach ($taxonomy_fields as $field) {
$field_load = $node
->get($field);
$values = $field_load
->getValue();
if (!empty($values)) {
foreach ($values as $term) {
$term_load = Term::load($term['target_id']);
$terms[] = [
'categoryName' => $term_load
->label(),
'categoryId' => (int) $term_load
->id(),
'isPrimary' => TRUE,
];
}
}
}
}
return $terms;
}
public function getCategoryList($ct, $username, $pass) {
if (!$this
->authenticate($username, $pass)) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_AUTH);
}
if (!$this
->validateBlogId($ct)) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_CT);
}
$categories = [];
$vocabularies = $this
->getCtVocabularies($ct);
if (!empty($vocabularies)) {
foreach ($vocabularies as $vocabulary_machine_name) {
$vocab_manager = $this->entityTypeManager
->getStorage('taxonomy_term');
$terms = $vocab_manager
->loadTree($vocabulary_machine_name);
foreach ($terms as $term) {
$categories[] = array(
'categoryName' => $term->name,
'categoryId' => $term->tid,
);
}
}
}
return $categories;
}
public function getCtVocabularies($ct) {
$definitions = $this->entityFieldManager
->getFieldDefinitions('node', $ct);
$vocabs = [];
foreach ($definitions as $field) {
if ($this
->fieldIsTaxonomy($field)) {
$settings = $field
->getSetting('handler_settings');
if (!empty($settings['target_bundles'])) {
foreach ($settings['target_bundles'] as $target) {
if (!in_array($target, $vocabs)) {
$vocabs[] = $target;
}
}
}
}
}
return $vocabs;
}
public function editPost($nid, $username, $pass, $data) {
$user = $this
->authenticate($username, $pass, TRUE);
if (!$user) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_AUTH);
}
$node = $this->entityTypeManager
->getStorage('node')
->load($nid);
if (!$node) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_NODE_NOT_FOUND, $nid);
}
if (!$node
->access('update', $user)) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_NODE_UPDATE, $nid);
}
if (!$this
->checkUserNodeAccess($user, $node)) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_NODE_UPDATE, $nid);
}
$content_type = $node
->getType();
$body_field = $this->blogapiConfig
->get('body_' . $content_type);
$comment_field = $this->blogapiConfig
->get('comment_' . $content_type);
$body = [
'value' => html_entity_decode($data['body']),
'format' => $this
->getValidTextFormat($data, $user),
];
$comment = [
'status' => isset($data['comments']) ? $data['comments'] : $this
->getDefaultCommentSetting($content_type),
];
$node
->set($body_field, $body);
$node
->set($comment_field, $comment);
$node
->setTitle($data['title']);
$node
->setPublished($data['publish']);
$node
->save();
return (string) $node
->id();
}
public function getValidTextFormat($data, $user) {
$format_load = FALSE;
if (isset($data['format'])) {
$format_load = $data['format'];
}
if (!$format_load || !array_key_exists($format_load, filter_formats())) {
$format_load = $this
->getDefaultFormat($user);
}
return $format_load;
}
public function setPostCategories($nid, $username, $pass, $data) {
$user = $this
->authenticate($username, $pass, TRUE);
if (!$user) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_AUTH);
}
$node = $this->entityTypeManager
->getStorage('node')
->load($nid);
if (!$node) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_NODE_NOT_FOUND, $nid);
}
if (!$node
->access('update', $user)) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_NODE_UPDATE, $nid);
}
if (!$this
->checkUserNodeAccess($user, $node)) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_NODE_UPDATE, $nid);
}
$content_type = $node
->getType();
$field_storage = [];
$taxonomy_fields = $this
->getTaxonomyFields($node);
$taxonomy_primary_field = $this->blogapiConfig
->get('taxonomy_' . $content_type);
$primary_field_bundles = [];
if (!is_null($taxonomy_primary_field)) {
$primary_field_bundles = $this
->getCtFieldTargetBundles($content_type, $taxonomy_primary_field);
}
foreach ($data as $item) {
$term = Term::load($item['categoryId']);
$vocab = $term
->getVocabularyId();
if (in_array($vocab, $primary_field_bundles)) {
$field_storage[$taxonomy_primary_field][] = $term
->id();
}
else {
foreach ($taxonomy_fields as $tax_field) {
$bundles = $this
->getCtFieldTargetBundles($content_type, $tax_field);
if (in_array($vocab, $bundles)) {
$field_storage[$tax_field][] = $term
->id();
break;
}
}
}
}
if (!empty($field_storage)) {
foreach ($field_storage as $field_id => $tags) {
$node
->set($field_id, $tags);
}
$node
->save();
}
return TRUE;
}
public function checkUserNodeAccess($user, $node) {
if ($user
->hasPermission('manage any content blogapi')) {
return TRUE;
}
$owner = $node
->getOwnerId();
if ($user
->id() === $owner) {
if ($user
->hasPermission('manage own content blogapi')) {
return TRUE;
}
}
return FALSE;
}
private function getCtFieldTargetBundles($ct, $field_name) {
$definitions = $this->entityFieldManager
->getFieldDefinitions('node', $ct);
$field = $definitions[$field_name];
$settings = $field
->getSetting('handler_settings');
return array_keys($settings['target_bundles']);
}
public function newPost($ct, $username, $pass, $data) {
$user = $this
->authenticate($username, $pass, TRUE);
if (!$user) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_AUTH);
}
if (!$this
->validateBlogId($ct)) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_CT);
}
if (!$user
->hasPermission('create ' . $ct . ' content')) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_NODE_CREATE);
}
$body_field = $this->blogapiConfig
->get('body_' . $ct);
$comment_field = $this->blogapiConfig
->get('comment_' . $ct);
$values = [
'type' => $ct,
'title' => $data['title'],
$body_field => [
'value' => html_entity_decode($data['body']),
'format' => $this
->getValidTextFormat($data, $user),
],
$comment_field => [
'status' => isset($data['comments']) ? $data['comments'] : $this
->getDefaultCommentSetting($ct),
],
'uid' => $user
->id(),
];
$node_manager = $this->entityTypeManager
->getStorage('node');
$node = $node_manager
->create($values);
$node
->setPublished($data['publish']);
$node
->save();
$id = $node
->id();
if (is_numeric($id)) {
return (string) $id;
}
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_NODE_NOT_FOUND);
}
public function getDefaultFormat($user) {
$format_load = $this->blogapiConfig
->get('text_format');
if ($format_load) {
return $format_load;
}
return filter_default_format($user);
}
public function getPost($nid, $username, $pass) {
$user = $this
->authenticate($username, $pass, TRUE);
if (!$user) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_AUTH);
}
$node = $this->entityTypeManager
->getStorage('node')
->load($nid);
if (!$node) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_NODE_NOT_FOUND, $nid);
}
if (!$node
->access('view', $user)) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_NODE_ACCESS, $nid);
}
return $node;
}
public function newMedia($ct, $username, $pass, $data) {
$user = $this
->authenticate($username, $pass, TRUE);
if (!$user) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_AUTH);
}
if (!$this
->validateBlogId($ct)) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_CT);
}
$uri = 'public://' . $data['name'];
$bits = $data['bits'];
$entity = file_save_data($bits, $uri);
if ($entity) {
$max_filesize = file_upload_max_size();
if ($max_filesize && $entity
->getSize() > $max_filesize) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_IMG_SIZE, $max_filesize);
}
$new_uri = $entity
->getFileUri();
$url = Url::fromUri(file_create_url($new_uri))
->toString();
return [
'url' => $url,
'struct',
];
}
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_IMG_SAVE);
}
public function deletePost($nid, $user, $pass) {
$user = $this
->authenticate($user, $pass, TRUE);
if (!$user) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_AUTH);
}
$node = $this->entityTypeManager
->getStorage('node')
->load($nid);
if (!$node) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_NODE_NOT_FOUND, $nid);
}
if (!$this
->checkUserNodeAccess($user, $node)) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_NODE_UPDATE, $nid);
}
if (!$node
->access('delete', $user)) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_NODE_DELETE, $nid);
}
$node
->delete();
return TRUE;
}
public function getTextFormats() {
$plugins = filter_formats();
$filters = [];
foreach ($plugins as $format) {
$filter['key'] = $format
->id();
$filter['label'] = $format
->get('name');
$filters[] = $filter;
}
return $filters;
}
public function publishPost($nid, $user, $pass, $publish = TRUE) {
$user = $this
->authenticate($user, $pass, TRUE);
if (!$user) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_AUTH);
}
$node = $this->entityTypeManager
->getStorage('node')
->load($nid);
if (!$node) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_NODE_NOT_FOUND, $nid);
}
if (!$this
->checkUserNodeAccess($user, $node)) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_NODE_UPDATE, $nid);
}
if (!$node
->access('edit', $user)) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_NODE_UPDATE, $nid);
}
$node
->setPublished($publish);
return TRUE;
}
public function getRecentPosts($ct, $user, $pass, $nr, $bodies = TRUE) {
$user = $this
->authenticate($user, $pass, TRUE);
if (!$user) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_AUTH);
}
if (!$this
->validateBlogId($ct)) {
return $this
->returnXmlError(self::BLOGAPI_XML_ERROR_CT);
}
$query = \Drupal::entityQuery('node')
->condition('type', $ct)
->sort('created', 'DESC')
->range(0, $nr);
if (!$user
->hasPermission('manage any content blogapi')) {
$query
->condition('uid', $user
->id());
}
$result = $query
->execute();
$response = [];
foreach ($result as $nid) {
$node = $this->entityTypeManager
->getStorage('node')
->load($nid);
$response[] = $this
->formatXml($node, $bodies);
}
return $response;
}
public function formatXml($node, $bodies = TRUE) {
$url = $node
->url();
$options = [
'absolute' => TRUE,
];
$externalUrl = Url::fromUri('internal:' . $url, $options)
->toString();
if ($node
->isPublished()) {
$post_status = 'published';
}
else {
$post_status = 'draft';
}
$xmlrpcval = array(
'userid' => $node
->getOwnerId(),
'dateCreated' => xmlrpc_date($node
->getCreatedTime()),
'title' => $node
->getTitle(),
'postid' => $node
->id(),
'link' => $externalUrl,
'permaLink' => $externalUrl,
'post_status' => $post_status,
);
if ($bodies) {
$content_type = $node
->getType();
$body_field = $this->blogapiConfig
->get('body_' . $content_type);
$body = $node
->get($body_field)
->getValue();
if (empty($body)) {
$body_value = '';
$format = $this
->getDefaultFormat(NULL);
}
else {
$body_value = $body[0]['value'];
$format = $body[0]['format'];
}
$comment_field = $this->blogapiConfig
->get('comment_' . $content_type);
$node_comment = $node->{$comment_field}
->getValue();
if ($node_comment[0]['status'] == CommentItemInterface::CLOSED) {
$comment = 2;
}
elseif ($node_comment[0]['status'] == CommentItemInterface::OPEN) {
$comment = 1;
}
else {
$comment = CommentItemInterface::HIDDEN;
}
$xmlrpcval['content'] = '<title>' . $node
->getTitle() . '</title>' . $body_value;
$xmlrpcval['description'] = $body_value;
$xmlrpcval['mt_allow_comments'] = $comment;
$xmlrpcval['mt_convert_breaks'] = $format;
}
return $xmlrpcval;
}
public function responseIsError($response) {
if ($response instanceof \stdClass && isset($response->is_error)) {
if ($response->is_error) {
return TRUE;
}
}
return FALSE;
}
public function getDefaultCommentSetting($ct) {
$definitions = $this->entityFieldManager
->getFieldDefinitions('node', $ct);
$field_name = $this->blogapiConfig
->get('comment_' . $ct);
$field = $definitions[$field_name];
$setting = $field
->getSetting('default_mode');
if (!is_null($setting)) {
return $setting;
}
return CommentItemInterface::CLOSED;
}
public function returnXmlError($error_code, $arg = 0) {
module_load_include('inc', 'xmlrpc', 'xmlrpc');
switch ($error_code) {
case self::BLOGAPI_XML_ERROR_AUTH:
return xmlrpc_error(401, t('Access denied.'));
case self::BLOGAPI_XML_ERROR_NODE_NOT_FOUND:
return xmlrpc_error(402, t('Node @nid not found.', [
'@nid' => $arg,
]));
case self::BLOGAPI_XML_ERROR_NODE_ACCESS:
return xmlrpc_error(403, t('Access to node @nid denied.', [
'@nid' => $arg,
]));
case self::BLOGAPI_XML_ERROR_NODE_UPDATE:
return xmlrpc_error(404, t('You do not have permission to update node @nid.', [
'@nid' => $arg,
]));
case self::BLOGAPI_XML_ERROR_CT:
return xmlrpc_error(405, t('Can not access content type with BlogAPI.'));
case self::BLOGAPI_XML_ERROR_NODE_CREATE:
return xmlrpc_error(406, t('You do not have permission to create this type of node.'));
case self::BLOGAPI_XML_ERROR_NODE_DELETE:
return xmlrpc_error(407, t('You do not have permission to delete node @nid.', $arg));
case self::BLOGAPI_XML_ERROR_IMG_SIZE:
return xmlrpc_error(408, t('Error uploading file because it exceeded the maximum filesize of @maxsize.', array(
'@maxsize' => format_size($arg),
)));
case self::BLOGAPI_XML_ERROR_IMG_SAVE:
return xmlrpc_error(409, t('Error storing file.'));
default:
return xmlrpc_error(400, t('Fatal error.'));
}
}
}