Add service consumers

parent e4221793
ws_endpoint: 'https://the.url'
ws_username: 'username'
ws_password: 'password'
verbose: true
NO_SAFE_CURL: false
......@@ -278,3 +278,27 @@ epal.applicant.creationpdf:
_controller: '\Drupal\epal\Controller\PdfCreator::createApplicantPDF'
requirements:
_user_is_logged_in: 'TRUE'
epal.svc.getdidacticyears:
path: '/epal/get-didactic-years'
options:
_auth: [ 'basic_auth' ]
defaults:
_controller: '\Drupal\epal\Controller\WSConsumer::getAllDidactiYear'
requirements:
_user_is_logged_in: 'TRUE'
epal.svc.getstudentpromotion:
path: '/epal/get-student-promotion/{didactic_year_id}/{lastname}/{firstname}/{father_firstname}/{mother_firstname}/{birthdate}/{registry_no}/{level_name}'
options:
_auth: [ 'basic_auth' ]
defaults:
_controller: '\Drupal\epal\Controller\WSConsumer::getStudentEpalPromotion'
requirements:
_user_is_logged_in: 'TRUE'
epal.svc.getstudentcertification:
path: '/epal/get-student-certification/{didactic_year_id}/{lastname}/{firstname}/{father_firstname}/{mother_firstname}/{birthdate}/{registry_no}/{level_name}'
options:
_auth: [ 'basic_auth' ]
defaults:
_controller: '\Drupal\epal\Controller\WSConsumer::getStudentEpalCertification'
requirements:
_user_is_logged_in: 'TRUE'
<?php
namespace Drupal\epal;
use Symfony\Component\HttpFoundation\Response;
use Exception;
/**
* Description of Client
*
*/
class Client
{
private $_settings = [
'verbose' => false,
'ws_endpoint' => '',
'ws_username' => '',
'ws_password' => '',
'NO_SAFE_CURL' => false
];
private $logger; // if this is set and settings sets verbose mode, it will be used for logging
private $_token = null; // cache JWT
private $_tokenExpirationTS = null; // try to calculate token expiration time
public function __construct($settings = [], $logger = null)
{
$this->logger = $logger;
$this->_settings = array_merge($this->_settings, $settings);
$this->_settings['ws_endpoint_token'] = "{$this->_settings['ws_endpoint']}/oauth2/token";
$this->_settings['ws_endpoint_token_granttype'] = 'password';
$this->_settings['ws_endpoint_studentepalinfo'] = "{$this->_settings['ws_endpoint']}/api/epal/GetStudentEpalInfo";
$this->_settings['ws_endpoint_studentepalcertification'] = "{$this->_settings['ws_endpoint']}/api/epal/GetStudentEpalCertification";
$this->_settings['ws_endpoint_studentepalpromotion'] = "{$this->_settings['ws_endpoint']}/api/epal/GetStudentEpalPromotion";
$this->_settings['ws_endpoint_alldidactiyear'] = "{$this->_settings['ws_endpoint']}/api/general/GetAllDidactiYear";
}
/**
* Επιστρέφει πίνακα με κλειδιά τα property names των πεδίων που επιστρέφει η GetStudentEpalInfo
* και τιμές λεκτικά - ετικέτες τους.
*
* @return array
*/
public function getStudentInfoFields()
{
return $this->studentInfoFields;
}
/**
* Λαμβάνει το authentication token
*
* @return string To authentication header (Bearer <token>) έτοιμο για να μπει στο authorization
* @throws \Exception
*/
public function getTokenBearer()
{
if ($this->_token !== null && $this->_tokenExpirationTS !== null && intval($this->_tokenExpirationTS) >= time()) {
$this->log(__METHOD__ . " reusing token");
return $this->_token;
}
$this->_token = null;
$this->_tokenExpirationTS = null;
$this->log(__METHOD__ . " new token");
$headers = [
'Accept: application/json',
'Accept-Language: en-gb',
'Audience: Any',
// 'Content-Type: application/x-www-form-urlencoded' // should be set by post
'User-Agent: OSTEAM Client/v1.1 osteam'
];
$payload = http_build_query([
'username' => $this->_settings['ws_username'],
'password' => $this->_settings['ws_password'],
'grant_type' => $this->_settings['ws_endpoint_token_granttype']
]);
$result = $this->post($this->_settings['ws_endpoint_token'], $payload, $headers);
if ($result['success'] === false) {
$this->log(__METHOD__ . " Error while calling ws. Diagnostic: {$result['response']}. Response code: {$result['http_status']}", "error");
throw new Exception("Προέκυψε λάθος κατά την άντληση των στοιχείων.");
}
if (($response = json_decode($result['response'], true)) !== null) {
$this->_tokenExpirationTS = time() + intval($response['expires_in']) - 15; // skip 15 seconds... just in case
$this->_token = ucfirst($response['token_type']) . " {$response['access_token']}";
return $this->_token;
} else {
$this->log(__METHOD__ . " Error while getting token from response {$result['response']}.", "error");
throw new Exception("Προέκυψε λάθος κατά την λήψη του token. Αδυναμία άντλησης του token από το response.");
}
}
/**
* Επιστρέφει λίστα των διδακτικών ετών με κλειδί το id και τιμή το λεκτικό.
*
* @return array Associative array με κλειδί το id και τιμή το λεκτικό. Π.χ.
* Array (
* [1] => 2008 - 2009
* [2] => 2011 - 2012
* [18] => 2013 - 2014
* [24] => 2016 - 2017
* )
*
* @throws \Exception Σε περίπτωση οποιουδήποτε λάθους
*/
public function getAllDidactiYear()
{
$this->log(__METHOD__);
$headers = [
'Accept: application/json',
'Accept-Language: en-gb',
'Audience: Any',
'Authorization: ' . $this->getTokenBearer(),
'User-Agent: OSTEAM Client/v1.1 osteam'
];
$result = $this->get($this->_settings['ws_endpoint_alldidactiyear'], [], $headers); // data as path params...
if ($result['success'] === false) {
$this->log(__METHOD__ . " Error while calling ws. Diagnostic: {$result['response']}. Response code: {$result['http_status']}", "error");
throw new Exception("Προέκυψε λάθος κατά την άντληση των στοιχείων.");
}
if (($response = json_decode($result['response'], true)) !== null) {
return $response;
} else {
$this->log(__METHOD__ . " Error while getting data from response {$result['response']}.", "error");
throw new Exception("Προέκυψε λάθος κατά την λήψη των στοιχείων. Αδυναμία άντλησης στοιχείων από την απάντηση.");
}
}
/**
*
* @param string $endpoint_base_url web service url
* @param int $didactic_year_id {@see getAllDidactiYear()}
* @param string $lastname μόνο χαρακτήρες, κενά και μεσαίες παύλες
* @param string $firstname μόνο χαρακτήρες, κενά και μεσαίες παύλες
* @param string $father_firstname μόνο χαρακτήρες, κενά και μεσαίες παύλες
* @param string $mother_firstname μόνο χαρακτήρες, κενά και μεσαίες παύλες
* @param string $birthdate ημερομηνίες στη μορφή 4-1-1997 (d-M-yyyy)
*
* @return boolean|null
* @throws \Exception Σε περίπτωση οποιουδήποτε λάθους
*/
public function getStudentEpalPromotionOrCertification($endpoint_base_url, $didactic_year_id, $lastname, $firstname, $father_firstname, $mother_firstname, $birthdate, $registry_no, $level_name)
{
$parts = explode('-', $birthdate, 3);
if (($parts === false) || count($parts) != 3 || checkdate(intval($parts[1]), intval($parts[0]), intval($parts[2])) === false) {
$this->log(__METHOD__ . " Mallformed birthdate", "error");
throw new Exception('Η ημερομηνία γέννησης πρέπει να είναι της μορφής Η/Μ/Ε', Response::HTTP_BAD_REQUEST);
}
if (mb_strlen($lastname) == 0 || mb_strlen($firstname) == 0 || mb_strlen($father_firstname) == 0 || mb_strlen($mother_firstname) == 0) {
$this->log(__METHOD__ . " Missing parameters", "error");
throw new Exception('Όλες οι παράμετροι είναι υποχρεωτικοί', Response::HTTP_BAD_REQUEST);
}
$data = [
'DidacticYearId' => intval($didactic_year_id),
'LastName' => $lastname,
'FirstName' => $firstname,
'FatherFirstName' => $father_firstname,
'MotherFirstname' => $mother_firstname,
'BirthDate' => $birthdate,
'RegistryNo' => $registry_no,
'LevelName' => $level_name
];
$headers = [
'Accept: application/json',
// 'Accept-Language: en-gb',
'Accept-Language: {"Accept-Language":"en-gb"}', // as per spec provided...
'Audience: Any',
'Authorization: ' . $this->getTokenBearer(),
'User-Agent: OSTEAM Client/v1.1 osteam'
];
$endpoint = $endpoint_base_url . array_reduce($data, function ($c, $v) {
$c .= "/" . urlencode($v);
return $c;
}, '');
$result = $this->get($endpoint, [], $headers); // data as path params...
if ($result['success'] === false) {
$this->log(__METHOD__ . " Error while calling ws. Diagnostic: {$result['response']}. Response code: {$result['http_status']}", "error");
throw new Exception("Προέκυψε λάθος κατά την άντληση των στοιχείων.");
}
// now return true/false/null ?
return $result['response'];
// if (($response = json_decode($result['response'], true)) !== null) {
// return $response;
// } else {
// throw new Exception("Προέκυψε λάθος κατά την λήψη των στοιχείων. Αδυναμία άντλησης στοιχείων από το response {$result['response']}");
// }
}
public function getStudentEpalPromotion($didactic_year_id, $lastname, $firstname, $father_firstname, $mother_firstname, $birthdate, $registry_no, $level_name)
{
$this->log(__METHOD__); // " $didactic_year_id, $lastname, $firstname, $father_firstname, $mother_firstname, $birthdate, $registry_no, $level_name");
return $this->getStudentEpalPromotionOrCertification($this->_settings['ws_endpoint_studentepalpromotion'], $didactic_year_id, $lastname, $firstname, $father_firstname, $mother_firstname, $birthdate, $registry_no, $level_name);
}
public function getStudentEpalCertification($didactic_year_id, $lastname, $firstname, $father_firstname, $mother_firstname, $birthdate, $registry_no, $level_name)
{
$this->log(__METHOD__); // " $didactic_year_id, $lastname, $firstname, $father_firstname, $mother_firstname, $birthdate, $registry_no, $level_name");
return $this->getStudentEpalPromotionOrCertification($this->_settings['ws_endpoint_studentepalcertification'], $didactic_year_id, $lastname, $firstname, $father_firstname, $mother_firstname, $birthdate, $registry_no, $level_name);
}
protected function setCommonCurlOptions($ch, $uri, $headers)
{
curl_setopt($ch, CURLOPT_URL, $uri);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_USERAGENT, "OSTEAM Client/v1.1 osteam");
if (isset($this->_settings['NO_SAFE_CURL']) && $this->_settings['NO_SAFE_CURL'] === true) {
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
}
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
if ($this->_settings['verbose']) {
curl_setopt($ch, CURLOPT_VERBOSE, true);
}
}
public function post($uri, $payload, $headers = [])
{
$ch = curl_init();
$this->setCommonCurlOptions($ch, $uri, $headers);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
if (curl_errno($ch)) {
$this->log(__METHOD__ . " Error calling {$uri}. Curl error: " . curl_error($ch) . " Curl info: " . var_export(curl_getinfo($ch), true), "error");
throw new Exception("Λάθος κατά την κλήση της υπηρεσίας.");
}
if (intval(($http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE)) / 100) != 2) {
return [
'success' => false,
'http_status' => $http_code,
'response' => $result
];
}
curl_close($ch);
return [
'success' => true,
'http_status' => $http_code,
'response' => $result
];
}
public function get($uri, $params = [], $headers = [])
{
$ch = curl_init();
if (is_array($params) && count($params) > 0) {
$qs = '?' . http_build_query($params);
} else {
$qs = '';
}
$this->setCommonCurlOptions($ch, "{$uri}{$qs}", $headers);
// curl_setopt($ch, CURLOPT_HTTPGET, true); // default
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
if (curl_errno($ch)) {
$this->log(__METHOD__ . " Error calling {$uri}. Curl error: " . curl_error($ch) . " Curl info: " . var_export(curl_getinfo($ch), true), "error");
throw new Exception("Λάθος κατά την κλήση της υπηρεσίας.");
}
if (intval(($http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE)) / 100) != 2) {
return [
'success' => false,
'http_status' => $http_code,
'response' => $result
];
}
curl_close($ch);
return [
'success' => true,
'http_status' => $http_code,
'response' => $result
];
}
protected function log($msg, $level = 'info')
{
if ($this->logger !== null && $this->_settings['verbose']) {
switch ($level) {
case 'info':
case 'warning':
case 'error':
$this->logger->$level($msg);
break;
default:
$this->logger->error($msg);
break;
}
}
return;
}
}
<?php
namespace Drupal\epal\Controller;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Drupal\Core\Database\Connection;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\epal\Client;
class WSConsumer extends ControllerBase
{
protected $entityTypeManager;
protected $logger;
protected $client;
protected $settings;
public function __construct(EntityTypeManagerInterface $entityTypeManager, LoggerChannelFactoryInterface $loggerChannel)
{
$config = $this->config('epal.settings');
foreach (['ws_endpoint', 'ws_username', 'ws_password', 'verbose', 'NO_SAFE_CURL'] as $setting) {
$this->settings[$setting] = $config->get($setting);
}
$this->entityTypeManager = $entityTypeManager;
$this->logger = $loggerChannel->get('epal-school');
$this->client = new Client($this->settings, $this->logger);
}
public static function create(ContainerInterface $container)
{
return new static(
$container->get('entity_type.manager'), $container->get('logger.factory')
);
}
public function getPing(Request $request)
{
return (new JsonResponse(['message' => 'Ping!!!']))
->setStatusCode(Response::HTTP_OK);
}
public function getAllDidactiYear()
{
$ts_start = microtime(true);
try {
$catalog = $this->client->getAllDidactiYear();
} catch (\Exception $e) {
return (new JsonResponse(['message' => $e->getMessage()]))
->setStatusCode(($code = $e->getCode()) == 0 ? Response::HTTP_INTERNAL_SERVER_ERROR : $code);
}
$duration = microtime(true) - $ts_start;
$this->logger->info(__METHOD__ . " :: timed [{$duration}]");
return (new JsonResponse([
'message' => 'Επιτυχία',
'data' => $catalog
]))
->setStatusCode(Response::HTTP_OK);
}
public function getStudentEpalPromotion($didactic_year_id, $lastname, $firstname, $father_firstname, $mother_firstname, $birthdate, $registry_no, $level_name)
{
$ts_start = microtime(true);
try {
$result = $this->client->getStudentEpalPromotion($didactic_year_id, $lastname, $firstname, $father_firstname, $mother_firstname, $birthdate, $registry_no, $level_name);
} catch (\Exception $e) {
return (new JsonResponse(['message' => $e->getMessage()]))
->setStatusCode(($code = $e->getCode()) == 0 ? Response::HTTP_INTERNAL_SERVER_ERROR : $code);
}
$duration = microtime(true) - $ts_start;
$this->logger->info(__METHOD__ . " :: timed [{$duration}]");
return (new JsonResponse([
'message' => 'Επιτυχία',
'data' => $result
]))
->setStatusCode(Response::HTTP_OK);
}
public function getStudentEpalCertification($didactic_year_id, $lastname, $firstname, $father_firstname, $mother_firstname, $birthdate, $registry_no, $level_name)
{
$ts_start = microtime(true);
try {
$result = $this->client->getStudentEpalCertification($didactic_year_id, $lastname, $firstname, $father_firstname, $mother_firstname, $birthdate, $registry_no, $level_name);
} catch (\Exception $e) {
return (new JsonResponse(['message' => $e->getMessage()]))
->setStatusCode(($code = $e->getCode()) == 0 ? Response::HTTP_INTERNAL_SERVER_ERROR : $code);
}
$duration = microtime(true) - $ts_start;
$this->logger->info(__METHOD__ . " :: timed [{$duration}]");
return (new JsonResponse([
'message' => 'Επιτυχία',
'data' => $result
]))
->setStatusCode(Response::HTTP_OK);
}
private function generateRandomString($length)
{
$characters = ['Α','Β','Γ','Δ','Ε','Ζ','Η','Θ','Ι','Κ','Λ','Μ','Ν','Ξ','Ο','Π','Ρ','Σ','Τ','Υ','Φ','Χ','Ψ','Ω'];
$charactersLength = count($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
return $randomString;
}
// private function respondWithStatus($arr, $s)
// {
// $res = new JsonResponse($arr);
// $res->setStatusCode($s);
// return $res;
// }
}
<div class = "loading" *ngIf="(showLoader$ | async) === true"></div>
<div class="loading" *ngIf="(showLoader$ | async) === true"></div>
<div id="headerNotice" (onHidden)="onHidden()" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header {{modalHeader | async}}" >
<h3 class="modal-title pull-left"><i class="fa fa-check-square-o"></i>&nbsp;&nbsp;{{ modalTitle | async }}</h3>
<div class="modal-header {{modalHeader | async}}">
<h3 class="modal-title pull-left"><i class="fa fa-check-square-o"></i>&nbsp;&nbsp;{{ modalTitle | async }}</h3>
<button type="button" class="close pull-right" aria-label="Close" (click)="hideModal()">
<span aria-hidden="true"><i class="fa fa-times"></i></span>
</button>
</div>
<div class="modal-body">
<p>{{ modalText | async }}</p>
<p>{{ modalText | async }}</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default pull-left" data-dismiss="modal">Κλείσιμο</button>
......@@ -18,20 +18,19 @@
</div>
</div>
<div class="header-wrapper">
<header id="navbar" role="banner" class="navbar navbar-default">
<header id="navbar" role="banner" class="navbar navbar-default">
<div *ngIf="(loginInfo$ | async).size > 0">
<ul class="navbar-nav">
<div *ngIf="(loginInfo$ | async).cu_name !== ''">
<div class="row">
<div class="offset-md-8 col-md-4 pull-right">
<span class="username">{{ cuName }}&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span class="signout isclickable" (click)="signOut()" style="color:#CC3300;">Αποσύνδεση&nbsp;&nbsp;</span>
<i class="fa fa-sign-out isclickable" (click)="signOut()"></i>
</div>
<ul class="navbar-nav">
<div *ngIf="(loginInfo$ | async).cu_name !== ''">
<div class="row">
<div class="offset-md-8 col-md-4 pull-right">
<span class="username">{{ cuName }}&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span class="signout isclickable" (click)="signOut()" style="color:#CC3300;">Αποσύνδεση&nbsp;&nbsp;</span>
<i class="fa fa-sign-out isclickable" (click)="signOut()"></i>
</div>
</div>
</div>
</ul>
</div>
</header>
</div>
</ul>
</div>
</header>
</div>
\ No newline at end of file
import {Component, OnInit, OnDestroy} from '@angular/core';
import {Router} from '@angular/router';
import {Component, OnInit, OnDestroy} from "@angular/core";
import {Router} from "@angular/router";
import { Injectable } from "@angular/core";
import { BehaviorSubject } from 'rxjs/Rx';
import { NgRedux, select } from 'ng2-redux';
import { IAppState } from '../../store/store';
import { ILoginInfo, ILoginInfoToken } from '../../store/logininfo/logininfo.types';
import { HelperDataService } from '../../services/helper-data-service';
import { LoginInfoActions } from '../../actions/logininfo.actions';
import { LOGININFO_INITIAL_STATE } from '../../store/logininfo/logininfo.initial-state';
import { SCHOOL_ROLE, STUDENT_ROLE, PDE_ROLE, DIDE_ROLE, MINISTRY_ROLE } from '../../constants';
import { EpalClassesActions } from '../../actions/epalclass.actions';
import { SectorFieldsActions } from '../../actions/sectorfields.actions';
import { RegionSchoolsActions } from '../../actions/regionschools.actions';
import { SectorCoursesActions } from '../../actions/sectorcourses.actions';
import { CriteriaActions } from '../../actions/criteria.actions';
import { StudentDataFieldsActions } from '../../actions/studentdatafields.actions';
import { BehaviorSubject } from "rxjs/Rx";
import { NgRedux, select } from "ng2-redux";
import { IAppState } from "../../store/store";
import { ILoginInfo, ILoginInfoToken } from "../../store/logininfo/logininfo.types";
import { HelperDataService } from "../../services/helper-data-service";
import { LoginInfoActions } from "../../actions/logininfo.actions";
import { LOGININFO_INITIAL_STATE } from "../../store/logininfo/logininfo.initial-state";
import { SCHOOL_ROLE, STUDENT_ROLE, PDE_ROLE, DIDE_ROLE, MINISTRY_ROLE } from "../../constants";
import { EpalClassesActions } from "../../actions/epalclass.actions";
import { SectorFieldsActions } from "../../actions/sectorfields.actions";
import { RegionSchoolsActions } from "../../actions/regionschools.actions";
import { SectorCoursesActions } from "../../actions/sectorcourses.actions";
import { CriteriaActions } from "../../actions/criteria.actions";
import { StudentDataFieldsActions } from "../../actions/studentdatafields.actions";
@Component({
selector: 'reg-header',
templateUrl: 'header.component.html'
selector: "reg-header",
templateUrl: "header.component.html"
})
export default class HeaderComponent implements OnInit, OnDestroy {
private authToken: string;
private authRole: string;
private cuName: string;
private loginInfo$: BehaviorSubject<ILoginInfo>;
public cuser :any;
public cuser: any;
private showLoader$: BehaviorSubject<boolean>;
private modalTitle: BehaviorSubject<string>;
private modalText: BehaviorSubject<string>;
......@@ -44,9 +44,9 @@ export default class HeaderComponent implements OnInit, OnDestroy {
private router: Router
) {
this.authToken = '';
this.authRole = '';
this.cuName = '';
this.authToken = "";
this.authRole = "";
this.cuName = "";
this.loginInfo$ = new BehaviorSubject(LOGININFO_INITIAL_STATE);
this.showLoader$ = new BehaviorSubject(false);
this.modalTitle = new BehaviorSubject("");
......@@ -56,7 +56,7 @@ export default class HeaderComponent implements OnInit, OnDestroy {
};
ngOnInit() {
(<any>$('#headerNotice')).appendTo("body");
(<any>$("#headerNotice")).appendTo("body");
this._ngRedux.select(state => {
if (state.loginInfo.size > 0) {
state.loginInfo.reduce(({}, loginInfoToken) => {
......@@ -64,7 +64,7 @@ export default class HeaderComponent implements OnInit, OnDestroy {
this.authRole = loginInfoToken.auth_role;
this.cuName = loginInfoToken.cu_name;
return loginInfoToken;
}, {})
}, {});
}
return state.loginInfo;
......@@ -73,7 +73,7 @@ export default class HeaderComponent implements OnInit, OnDestroy {
}