TYPO3 11 LTS Generation of Frontend Url in REST API Context - typo3

Hi I need some support regarding frontend url generation inside building REST API. I'm using restler for the API.
I could generate the url with
$site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByPageId($arguments['pageUid']);
return (string)$site->getRouter()->generateUri($arguments['pageUid'],$queryStrings);
But the problem is it is not building the extension parameters using the routing configuration. The url works as expected.
Update:
To get more understanding: I added the info more.
This is same like generating a frontend url in backend, scheduler task or command controller. Where GLOBALS['TSFE'] not available.
I use the above function like this.
public function generateUrl(
int $pageId,
array $arguments,
bool $absolute
): string
{
$site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByPageId($pageId);
if (empty($site->getBase()->getHost()) || empty($site->getBase()->getScheme())) {
throw new \RuntimeException(
"Site " . $site->getIdentifier() . ' does not have proper schema or host set. Thus not usable in cli context.',
1648736865
);
}
$uri = $site
->getRouter()
->generateUri(
$pageId,
$arguments,
'',
PageRouter::ABSOLUTE_URL
);
if (empty($uri->getHost()) || empty($uri->getScheme())) {
throw new \RuntimeException(
'Build uri did not have proper schema or host set. Thus not usable in cli context. ' . (string)$uri,
1648736938
);
}
if (!$absolute) {
return $uri->getPath() . (!empty($uri->getQuery()) ? '?' . $uri->getQuery() : '');
}
return (string)$uri;
}
Any Idea ?

if you have PageUid already and Arguments then you can try building URI with UriBuilder of TYPO3.
TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder
$uriBuilder = $renderingContext->getControllerContext()->getUriBuilder();
$uriBuilder->reset();
if ($pageUid > 0) {
$uriBuilder->setTargetPageUid($pageUid);
}
if ($pageType > 0) {
$uriBuilder->setTargetPageType($pageType);
}
if ($noCache === true) {
$uriBuilder->setNoCache($noCache);
}
if (is_string($section)) {
$uriBuilder->setSection($section);
}
if (is_string($format)) {
$uriBuilder->setFormat($format);
}
if (is_array($additionalParams)) {
$uriBuilder->setArguments($additionalParams);
}
if ($absolute === true) {
$uriBuilder->setCreateAbsoluteUri($absolute);
}
if ($addQueryString === true) {
$uriBuilder->setAddQueryString($addQueryString);
}
if (is_array($argumentsToBeExcludedFromQueryString)) {
$uriBuilder->setArgumentsToBeExcludedFromQueryString($argumentsToBeExcludedFromQueryString);
}
if ($addQueryStringMethod !== '') {
$uriBuilder->setAddQueryStringMethod($addQueryStringMethod);
}
if ($linkAccessRestrictedPages === true) {
$uriBuilder->setLinkAccessRestrictedPages($linkAccessRestrictedPages);
}
return $uriBuilder->uriFor($action, $arguments, $controller, $extensionName, $pluginName);

I got my problem.
The issue was with the arguments I supplied to the generate Url function.
I prepared the arguments like this:
array(3) {
["tx_vshcore_profilesdetail[action]"]=>
string(6) "detail"
["tx_vshcore_profilesdetail[controller]"]=>
string(8) "Profiles"
["tx_vshcore_profilesdetail[profile]"]=>
int(1)
}
I think about the PHP function http_build_query and prepare my arguments like the above. But it should be like this.
array(1) {
["tx_vshcore_profilesdetail"]=>
array(3) {
["controller"]=>
string(8) "Profiles"
["action"]=>
string(6) "detail"
["profile_detail"]=>
int(3)
}
}
I hope it is clear where I'm wrong :).  

Related

How to redirect to url within same context

I have /logout action, that should redirect to /login. /login renders template, where I read flash message from context. This works, but url in browser is still remains "/logout":
router.get("/logout").handler((ctx) => {
if (ctx.user()!=null) {
ctx.clearUser()
//flash message
ctx.put("msg", "Logout succeed")
}
ctx.reroute("/login")
})
What I want, but url should be "/login":
Better to use(?):
ctx.response.putHeader("location", "/login").setStatusCode(302).end()
But there is different context. So I haven't flash message.
How to redirect to /login within same context?
Upd.
Question related to this issue
In order to work with flash messages you should add a cookie to the redirect with the content:
// this makes the message available to the client
ctx
.addCookie(Cookie.cookie("flashMessage", "Logout succeed"));
// configure where to redirect
ctx.response()
.putHeader("location", "/login");
// perform the redirect
ctx.end(302);
Then on the client side you need a bit of JavaScript to read the message and
perform the display as you wish. Since there is no simple way to read cookies on the browser if you're using jQuery with the cookie plugin you can do something like:
$.fn.flashMessage = function (options) {
var target = this;
options = $.extend({}, options, { timeout: 3000 });
if (!options.message) {
options.message = getFlashMessageFromCookie();
deleteFlashMessageCookie();
}
if (options.message) {
if (typeof options.message === "string") {
target.html("<span>" + options.message + "</span>");
} else {
target.empty().append(options.message);
}
}
if (target.children().length === 0) return;
target.fadeIn().one("click", function () {
$(this).fadeOut();
});
if (options.timeout > 0) {
setTimeout(function () { target.fadeOut(); }, options.timeout);
}
return this;
function getFlashMessageFromCookie() {
return $.cookie("FlashMessage");
}
function deleteFlashMessageCookie() {
$.cookie("FlashMessage", null, { path: '/' });
}
};
And add a placeholder in your HTML like:
<div id="flash-message"></div>
And trigger it like:
$(function() {
$("#flash-message").flashMessage();
});

spray authenticate directive returns different HTTP status codes

I am trying a basic authentication on post request in spray.io 1.3.2 using authenticate directive. My code looks following:
val route: Route = {
pathPrefix("ato") {
pathPrefix("v1") {
path("orders" / "updateStatus") {
post {
authenticate(BasicAuth(userPasswordAuthenticator _, realm = "bd ato import api")) {
user =>
entity(as[String]) {e =>
complete {
s"Hello $e "
}
}
}
}
}
}
}
}
def userPasswordAuthenticator(userPass: Option[UserPass]): Future[Option[String]] =
Future {
if (userPass.exists(up => up.user == ato_import_v1_usr && up.pass == ato_import_v1_pwd)) Some("ato_v1")
else None
}
This works perfectly fine, authorized Status Ok 200, unauthorized 401. However when the order of directives is changed as follows:
val route: Route = {
pathPrefix("ato") {
pathPrefix("v1") {
authenticate(BasicAuth(userPasswordAuthenticator _, realm = "bd ato import api")) {
user =>
path("orders" / "updateStatus") {
post {
entity(as[String]) {e =>
complete {
s"Hello $e "
}
}
}
}
}
}
}
}
I am getting Status 405, HTTP method not allowed for unauthorized access. I am not sure why that happens. From certain point it make sense, path is not matched because of missing credentials etc.
Could someone please clarify that?
The reason why I wanted to put authorization at v1 level is that I wanted to make every version protected by different password. Is there a way how to achieve that? What is the best practice in chaining directives?
I would like to follow DRY principle.
Thanks

where to put facebook ajax sign in file

i'm currently trying to migrate my site to yii. (still new to it too) in my site i have a facebook login code that looks like this
function updateButton(response) {
var b = document.getElementById("{$this->fbLoginButtonId}");
b.onclick = function(){
$("#{$this->fbLoginButtonId}").button("loading");
FB.login(function(response) {
if(response.authResponse) {
$('#processing').modal({show: true, backdrop: 'static', keyboard: false});
FB.api('/me', function(user) {
$.ajax({ type : 'post'
, url: '{$this->facebookLoginUrl}'
, data: ({ user: user })
, dataType: 'json'
, success: function(data){
if(data.error == 0){
window.location.href = data.success;
} else {
$('#processing').modal('hide');
showError(data.error);
$("#{$this->fbLoginButtonId}").button("reset");
}
}
});
});
} else { $("#{$this->fbLoginButtonId}").button("reset"); }
}, {scope: '{$this->facebookPermissions}'});
}
}
the line url: '{$this->facebookLoginUrl}' basically points to the file that does the authentication. in Yii, i put that file in protected/controllers/facebookcontroller.php
class FacebookController extends Controller {
public $defaultAction = 'facebook';
public function actionFacebook() {
if (app()->request->isAjaxRequest) {
$user = app()->request->getParam('user');
Shared::debug($user);
// verify one last time that facebook knows this guy
if($user['id'] === app()->facebook->getUser()){
$model = User::model()->findByEmail($user['email']);
if(!empty($model)){
// facebook email matches one in the user database
$identity = new UserIdentity( $model->email , null );
$identity->_ssoAuth = true;
$identity->authenticate();
if($identity->errorCode === UserIdentity::ERROR_NONE){
app()->user->login($identity, null);
echo json_encode(array('error' => false, 'success' => url('/')));
app()->end();
} else {
echo json_encode(array('error' => 'System Authentication Failed', 'code' => 'auth'));
app()->end();
}
} else {
// nothing found, this person should register
// write query to input into database!!!
}
} else {
// fb user id past from ajax does not match who facebook says they are...
echo json_encode(array('error' => 'Facebook Authentication Failed', 'code' => 'fb_auth'));
app()->end();
}
} else {
throw new CHttpException(403);
}
}
}
basically what do i put here url: '{$this->facebookLoginUrl}' ?? i tried http://localhost/facebook.html but doesn't work. i get this error on firebug
<h1>PHP Error [8]</h1>
<p>Undefined index: email (/Applications/XAMPP/xamppfiles/htdocs/protected/controllers/FacebookController.php:13)</p>
<pre>#0 /Applications/XAMPP/xamppfiles/htdocs/protected/controllers/FacebookController.php(13): CWebApplication->handleError()
#1 /Applications/XAMPP/xamppfiles/htdocs/yii/web/actions/CInlineAction.php(49): FacebookController->actionFacebook()
#2 /Applications/XAMPP/xamppfiles/htdocs/yii/web/CController.php(308): CInlineAction->runWithParams()
#3 /Applications/XAMPP/xamppfiles/htdocs/yii/web/CController.php(286): FacebookController->runAction()
#4 /Applications/XAMPP/xamppfiles/htdocs/yii/web/CController.php(265): FacebookController->runActionWithFilters()
#5 /Applications/XAMPP/xamppfiles/htdocs/yii/web/CWebApplication.php(282): FacebookController->run()
#6 /Applications/XAMPP/xamppfiles/htdocs/yii/web/CWebApplication.php(141): CWebApplication->runController()
#7 /Applications/XAMPP/xamppfiles/htdocs/yii/base/CApplication.php(180): CWebApplication->processRequest()
#8 /Applications/XAMPP/xamppfiles/htdocs/index.php(25): CWebApplication->run()
</pre>
the ajax post response looks like this..
user[birthday] MM/DD/YYYY
user[first_name] name
user[gender] male
user[hometown][id] 106031246101856
user[hometown][name] CITY, STATE
user[id] 598482999
user[last_name] LASTNAME
user[link] https://www.facebook.com/ID
user[locale] en_US
user[location][id] 106031246101856
user[location][name] CITY, STATE
user[middle_name] MIDDLENAME
user[name] FULLNAME
user[timezone] -8
user[updated_time] 2013-12-15T16:43:03+0000
user[username] USERNAME
user[verified] true
Yii generates url as http://www.example.com/index.php?r={controller_id}/{action_id}.
So in your case url will be http://www.example.com/index.php?r=facebook/facebook.
Learn how yii manges url's here.

Codeigniter-restserver does not accept POST method CORS

I'm developing a REST API using Codeigniter-restserver for a mobile applications in Phonegap.
Since Phonegap loads index.html using file://, my API should support CORS. And I'm new to this CORS.
I've set headers in libraries/REST_Controller.php
header("Access-Control-Allow-Origin: *");
header('Access-Control-Allow-Headers:Origin, X-Requested-With, Content-Type, Accept');
And I'm using Backbone.js.
Here is my Controller
// This can be removed if you use __autoload() in config.php OR use Modular Extensions
require APPPATH.'/libraries/REST_Controller.php';
class Prop extends REST_Controller
{
public function __construct()
{
parent::__construct();
$this->load->database();
}
function property_get()
{
...
}
function property_post()
{
...
}
function attach_image($file_type)
{
if($this->post($file_type) != ""){
save_base64_image($file_type,$this->post($file_type));
$this->email->attach($_SESSION[$file_type]);
}
}
function property_delete()
{
...
}
function share_post()
{
$email_id = $this->post('emailid');
$config['mailtype'] = "html";
$this->email->initialize($config);
$this->email->from('myid#gmail.com', 'mobile app');
$this->email->to($email_id);
$this->email->subject('subject');
$this->email->message('message');
if ( ! $this->email->send() )
{
$this->response("Internal server error.", 500);
}
else
{
$result = new stdClass();
$result->message = 'Email has been sent.';
$this->response($result, 200); // 200 being the HTTP response code
}
}
public function send_post()
{
var_dump($this->request->body);
}
public function send_put()
{
var_dump($this->put('foo'));
}
}
Here's my jQuery ajax call.
$.ajax( {
url: PMSApp.apiUrl + "/share/format/json",
type: 'post',
dataType: "json",
contentType: "application/json; charset=utf-8"
})
.done(function(response) {
console.log(JSON.stringify(response));
})
.fail(function(response) {
console.log(JSON.stringify(response));
})
.always(function(response) {
console.log(JSON.stringify(response));
});
I'm able to access this /share/format/json API with POSTMAN, chrome extension, but not with file:// or localhost://.
EDIT:
I've also tried changing share_post() to share_gett(), It worked. But i need it in POST.
I'm stuck on this for the past 48 hours. Tried many solutions, but nothing helped me with this issue. Please help me.
Phonegap provides option to whitelist your webservice domain. It is set up the access origin in config xml
http://docs.phonegap.com/en/2.3.0/guide_whitelist_index.md.html
You have to start Chrome with Access-Control-Allow-Origin
This thread:
https://superuser.com/questions/384871/overriding-access-control-allow-origin-restriction-in-google-chrome
Check this tread:
Origin is not allowed by Access-Control-Allow-Origin

What are different between Backend vs Frontend Cache of Zend Framework

I am implementing caching for my website which is using Zend Framework.
I look into the source code and see that:
Zend_Cache::factory()
always need two configurations of backend and frontend.
And my issue is:
I don't know why backend is set inside frontend,
and what is the difference between them?
$frontendObject->setBackend($backendObject);
return $frontendObject;
Here is the orginal source code:
public static function factory($frontend, $backend, $frontendOptions = array(), $backendOptions = array(), $customFrontendNaming = false, $customBackendNaming = false, $autoload = false)
{
if (is_string($backend)) {
$backendObject = self::_makeBackend($backend, $backendOptions, $customBackendNaming, $autoload);
} else {
if ((is_object($backend)) && (in_array('Zend_Cache_Backend_Interface', class_implements($backend)))) {
$backendObject = $backend;
} else {
self::throwException('backend must be a backend name (string) or an object which implements Zend_Cache_Backend_Interface');
}
}
if (is_string($frontend)) {
$frontendObject = self::_makeFrontend($frontend, $frontendOptions, $customFrontendNaming, $autoload);
} else {
if (is_object($frontend)) {
$frontendObject = $frontend;
} else {
self::throwException('frontend must be a frontend name (string) or an object');
}
}
$frontendObject->setBackend($backendObject);
return $frontendObject;
}
The cache backend is the "cache engine" : it can be file, memcached, etc.
The cache frontend specify what kind of data will be stored in the cache (see http://framework.zend.com/manual/1.12/en/zend.cache.frontends.html)