get file like pics and media through controller - kohana

I have the following link on my website - http://mywebsite/multimedia/pronounciation/265.mp3
which gets me the file bypassing controllers. But I would like to log request and then return this file. So I created controller which logs request and then reroutes to the file:
class Controller_GetSound extends Controller {
public function action_index() {
Request::factory('multimedia/pronounciation/265.mp3')
->method(Request::POST)
->post($this->request->post())
->execute();
}
}
But it doesn't work as expected. How can I return resource file from controller?

Kohana has a send_file function. That function does a good job on splitting large files and sending correct mime types.
#see http://kohanaframework.org/3.3/guide-api/Response#send_file
Your code should be:
class Controller_GetSound extends Controller {
public function action_index() {
$this->response->send_file('multimedia/pronounciation/265.mp3',TRUE,array(
'mime_type' => 'audio/mpeg',
))
}
}
You actually don't really need to set the mime_type. Kohana will find the correct mime_type for your.

It sounds like you want to implement something known as X-Sendfile. I think?
The controller would look something like this:
class Controller_GetSound extends Controller {
public function action_index() {
$this->response->headers(array(
'Content-Type' => 'audio/mpeg'
'X-Sendfile' => 'multimedia/pronounciation/265.mp3',
);
}
}

Related

Custom param decorator which transform param to database entity

In Laravel (php) has route /article/:article, and in controller method I get the model:
function getArticle(ArticleModel $article) {...}
How to make this in NestJS?
My controller:
#Controller('/articles')
export class ArticlesController {
#Get('/:article/edit')
editArticle(#Param('article') articleId: number) {...}
}
How to transform #Param('article') to custom decorator #ArticleParam() which will return my Article entity by id in request?
You can implement a custom pipe that injects a TypeORM repository and returns the database entity when prompted with an ID, something like this:
#Injectable()
export class ArticlePipe implements PipeTransform {
constructor(#InjectRepository(Article) private repository: Repository<Article>) {}
transform(value: id, metadata: ArgumentsMetadata): Promise<Article|null> {
return this.repository.findOneBy({ id });
}
}
Then use it like
#Get('/article/:id')
getArticle(#Param('id', ArticlePipe) article: Article) { ... }
You just need to make sure to use the pipe only on modules that provide the Article EntityRepository.
Then, if you need the specific #ArticleParam, it should be like this:
export function ArticleParam = () => applyDecorators(
Param(ArticlePipe)
)

How to use any of i18n packages in nestjs mvc?

I found this package nest-18n but that dudes thinks that nestjs is only used for api and not mvc.
So sure ?lang=en or ?lang=de works and it changes language but question is how to use that on view?
My first thought was that this is working out of the box with __("Something to translate"). But that will not work (__ is undefined).
Since i18Service.translate method is async you can not add it to view (there is pug then but that is horrible idea). Idea of adding anything on the the view that is async does not make sense at all. So in principle they made package that can not be used outside of api's.
Other thing that i can do is to have something like
class AppController extends BaseController() {
#Get("/")
index() {
return {
someTranslation: await this.getTranslation("give me something to translate"),
// IMAGINE NOW Having 1000 OF TRANSLATION ON INDEX PAGE
}
}
}
where BaseController is:
class BaseController() {
constructor(private readonly i18n: I18nService, lang: string) {
}
async protected getTranslation(stringToTranslate: string) {
return await this.i18n(stringToTranslate, {lang});
}
}
Does anyone have idea how to use any of i18n in nestjs mvc?

Auto-fill DTO fields with other data than request body data

I have a class CreateFolderDto with two readonly fields:
export class CreateFolderDto {
public readonly name: string
public readonly user_id: number
}
I have a controller which is:
#UseGuards(AuthGuard('jwt'))
#Post()
public create(#Request() req, #Body() createFolderDto: CreateFolderDto) {
return this.folderService.create(createFolderDto)
}
The request send to my controller is a good one, I only send the name in json format with an accessToken in the header. The accessToken permit me to get my user_id from the request with req.user.id.
The DTO field user_id is not automatically filled. I would like to fill it automatically.
Is it a way to auto-fill my createFolderDto.user_id variable ?
#Body only wraps actual request body into instance of the CreateFolderDto class. As the body which comes to your endpoint has no such a field, you need to add it manually.
Normally, aggregated fields could be added with custom constructor of your DTO:
export class CreateFolderDto {
public readonly name: string
public readonly session_uuid: string
constructor(bodyValue: any = {}) {
this.name = bodyValue.name
this.session_uuid = generateUuid()
}
}
But in your case, user is attached to request itself, so I believe you have the following options:
Check out your code which attaches the user to request itself. If you are using JWT Auth described in NestJS docs, you cannot do this that way.
You can write custom Interceptor:
Injectable()
export class ExtendBodyWithUserId implements NestInterceptor {
async intercept(context: ExecutionContext, next: CallHandler) {
const request = context.switchToHttp().getRequest()
request.body.user_id = request.user
return next.handle()
}
}
// usage
#UseGuards(AuthGuard('jwt'))
#UseInterceptors(ExtendBodyWithUserId)
#Post()
public create(#Request() req, #Body() createFolderDto: CreateFolderDto) {
return this.folderService.create(createFolderDto)
}
Last but not least, some personal recommendation. Consider how much you will use this interceptor as an extension, as too many of 'extras' like this bloat the codebase.
I would recommend to change the folderService signature to:
create(createFolderDto: CreateFolderDto, user: User), where folder dto has only the name, without user-related entry. You keep the consistency, separation and clear intentions. In the implementation of create you can just pass user.id further.
And going this way, you don't have to write custom interceptors.
Pick your way and may the consistency in your codebase be with you!

Kohana - one function on every controller

I have a project in Kohana 3.3.
I have a lot of controllers, models etc.
Now, I want add one functionality - close the whole site for all users.
Where I can add function, which for example, will redirect users to http://mypage.com/website_is_close ?
Example:
function check(){
$isClose = DB::query(.....)
if($isClose) header("Location: http://mypage.com/website_is_close");
return false;
}
Thanks :)
In Controller_Base all other controllers extend from. E.g.
File application/classes/Controller/Base.php
class Controller_Base extends Controller_Template {
public function before()
{
$isClose = DB::query(.....)
if($isClose)
{
HTTP::redirect("http://mypage.com/website_is_close");
exit ;
}
parent::before();
}
}
All other classes should extend from that class e.g
class Controller_Home extends Controller_Base {}
I personally use this also for every subdirectory e.g.
// As all controllers in the user folder probably need to be supplied with a user anyway
class Controller_User_Base extends Controller_Base {}
class Controller_User_Profile extends Controller_User_Base {}
I think a better approach would be to add a "catch all" route to the beginning of your routes list.
It would catch all URLs and would point to a controller that you would create. This is far cleaner than hacking away at a base controller.
How does this look?
Route::set('closed', '(<url>)', array('url' => '.*'))
->defaults(array(
'controller' => 'Closed',
'action' => 'index',
));

Black-hole error when route pointed to a class that extends plugin and uses extended class

In routes I have
Router::connect('/opauth-complete/*', array('controller' => 'app_users', 'action' => 'opauth_complete'));
If I change pointer to controller app_users with anything else and create controller everything works with no error. But I need it to work with AppUsersController.
AppUsersController looks like this
App::uses('UsersController', 'Users.Controller');
class AppUsersController extends UsersController {
public function beforeFilter() {
parent::beforeFilter();
$this->User = ClassRegistry::init('AppUser');
}
// ...
// ...
public function opauth_complete() {
die(1);
}
// ...
// ...
}
So, plugin is CakeDC Users and another plugin that goes to /example/callback after /example/auth/facebook is Opauth plugin.
Error message looks like this
The request has been black-holed
Error: The requested address '/example/opauth-complete' was not found on this server.
This is perfectly possible to make these two plugins work together; when browser points to /example/auth/facebook, it redirects to /example/auth/callback and somehow it needs opauth-complete route to link to specific method.
All works if not pointed to app_users that extends plugin, uses plugin. Does not work only with this case. How can users of these two plugins get around such situation.
I solved it by disabling Security component on Opauth action in my AppUsersController. Thing is that Opauth transfers data using POST and you should either change a method of it (ie: use Sessions, GET) or disable Security component.
For a method change use this in your bootstrap.php or core.php
Configure::write('Opauth.callback_transport', 'session'); // you can try 'get' too
To follow my approach add this to a controller where error occurs and where you place your opauth_complete method
public function beforeFilter() {
// ...
if (isset($this->Security) && $this->action == 'opauth_complete') {
$this->Security->validatePost = false;
$this->Security->csrfCheck = false;
}
// ...
}
P.S. Changing method to Sessions has its drawbacks, you can take a look at comments here at Github Opauth issue #16

Resources