Initial commit

This commit is contained in:
Oshane Bailey 2024-06-16 12:39:16 +00:00
commit 952ca5e52a
19 changed files with 440 additions and 0 deletions

24
.gitignore vendored Normal file
View file

@ -0,0 +1,24 @@
ApiExtender*.zip
/vendor/
node_modules/
npm-debug.log
yarn-error.log

# Laravel 4 specific
bootstrap/compiled.php
app/storage/

# Laravel 5 & Lumen specific
public/storage
public/hot

# Laravel 5 & Lumen specific with changed public path
public_html/storage
public_html/hot

storage/*.key
.env
Homestead.yaml
Homestead.json
/.vagrant
.phpunit.result.cache

View file

View file

@ -0,0 +1,96 @@
<?php

namespace Modules\ApiExtender\Http\Controllers;

use App\Conversation;
use App\Mailbox;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Response;
use Illuminate\Http\Request;
use Modules\KnowledgeBase\Entities\KbCategory;
use Modules\KnowledgeBase\Entities\KbArticle;
use Modules\KnowledgeBase\Entities\KbArticleKbCategory;

class KnowledgeBaseApiController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
}

public function get(Request $request, $mailboxId)
{
$mailbox = Mailbox::findOrFail($mailboxId);
if ($mailbox === null) {
return Response::json([], 404);
}
$categories = \KbCategory::getTree($mailbox->id, [], 0, true);

$locale = $request->input('locale') ?? \Kb::defaultLocale($mailbox);

$items = [];

foreach ($categories as $c) {
if (!$c->checkVisibility()) {
continue;
}
$items[] = (object)[
'id' => $c->id,
'name' => $c->getAttributeInLocale('name', $locale),
'description' => $c->getAttributeInLocale('description', $locale)
];

}

return Response::json([
'mailbox_id' => $mailbox->id,
'name' => $mailbox->name,
'categories' => $items,
], 200);

}

public function category(Request $request, $mailboxId, $categoryId)
{
$mailbox = Mailbox::findOrFail($mailboxId);
if ($mailbox === null) {
return Response::json([], 404);
}

$category = KbCategory::findOrFail($categoryId);
if (!$category->checkVisibility()) {
$category = null;
}
if ($category === null) {
return Response::json([], 404);
}
$articles = [];
if ($category) {
$sortedArticles = $category->getArticlesSorted(true);
}

$locale = $request->input('locale') ?? \Kb::defaultLocale($mailbox);

foreach ($sortedArticles as $a) {
$a->setLocale($locale);
$articles[] = (object)['id' => $a->id, 'title' => $a->getAttributeInLocale('title', $locale), 'text' => $a->getAttributeInLocale('text', $locale)];
}

return Response::json([
'id' => 0,
'mailbox_id' => $mailbox->id,
'name' => $mailbox->name,
'category' => (object)[
'id'=>$category->id,
'name'=>$category->getAttributeInLocale('name', $locale),
'description'=>$category->getAttributeInLocale('description', $locale),
],
'articles' => $articles,
], 200);
}

}

View file

@ -0,0 +1,96 @@
<?php

namespace Modules\ApiExtender\Http\Controllers;

use App\Conversation;
use App\Mailbox;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Response;
use Illuminate\Http\Request;
use Modules\KnowledgeBase\Entities\KbCategory;
use Modules\KnowledgeBase\Entities\KbArticle;
use Modules\KnowledgeBase\Entities\KbArticleKbCategory;

class ReportApiController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
}

public function get(Request $request, $mailboxId)
{
$mailbox = Mailbox::findOrFail($mailboxId);
if ($mailbox === null) {
return Response::json([], 404);
}
$categories = \KbCategory::getTree($mailbox->id, [], 0, true);

$locale = $request->input('locale') ?? \Kb::defaultLocale($mailbox);

$items = [];

foreach ($categories as $c) {
if (!$c->checkVisibility()) {
continue;
}
$items[] = (object)[
'id' => $c->id,
'name' => $c->getAttributeInLocale('name', $locale),
'description' => $c->getAttributeInLocale('description', $locale)
];

}

return Response::json([
'mailbox_id' => $mailbox->id,
'name' => $mailbox->name,
'categories' => $items,
], 200);

}

public function category(Request $request, $mailboxId, $categoryId)
{
$mailbox = Mailbox::findOrFail($mailboxId);
if ($mailbox === null) {
return Response::json([], 404);
}

$category = KbCategory::findOrFail($categoryId);
if (!$category->checkVisibility()) {
$category = null;
}
if ($category === null) {
return Response::json([], 404);
}
$articles = [];
if ($category) {
$sortedArticles = $category->getArticlesSorted(true);
}

$locale = $request->input('locale') ?? \Kb::defaultLocale($mailbox);

foreach ($sortedArticles as $a) {
$a->setLocale($locale);
$articles[] = (object)['id' => $a->id, 'title' => $a->getAttributeInLocale('title', $locale), 'text' => $a->getAttributeInLocale('text', $locale)];
}

return Response::json([
'id' => 0,
'mailbox_id' => $mailbox->id,
'name' => $mailbox->name,
'category' => (object)[
'id'=>$category->id,
'name'=>$category->getAttributeInLocale('name', $locale),
'description'=>$category->getAttributeInLocale('description', $locale),
],
'articles' => $articles,
], 200);
}

}

5
Http/routes.php Normal file
View file

@ -0,0 +1,5 @@
<?php
Route::group(['prefix' => \Helper::getSubdirectory(), 'namespace' => 'Modules\ApiExtender\Http\Controllers'], function () {
Route::get('/api/knowledgebase/{mailboxId}/categories', ['uses' => 'KnowledgeBaseApiController@get', 'laroute' => false])->name('knowledgebase.index');
Route::get('/api/knowledgebase/{mailboxId}/categories/{categoryId}', ['uses' => 'KnowledgeBaseApiController@category', 'laroute' => false])->name('knowledgebase.category');
});

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License

Copyright (c) 2022 @jtorvald

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

0
Providers/.gitkeep Normal file
View file

View file

@ -0,0 +1,43 @@
<?php

namespace Modules\ApiExtender\Providers;

use Illuminate\Support\ServiceProvider;

class ApiExtenderServiceProvider extends ServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = false;

/**
* Boot the application events.
*
* @return void
*/
public function boot()
{
$this->hooks();
}

/**
* Module hooks.
*/
public function hooks()
{

}

/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return [];
}
}

0
Public/.gitkeep Normal file
View file

38
Public/images/module.svg Normal file
View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="256px" height="256px" viewBox="0 0 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>module</title>
<defs>
<path d="M62,3.00122599 C62,1.35349407 60.6354067,0 58.9741627,0 L11.6435407,0 C5.14688995,0 0,5.10502656 0,11.4017164 C0,11.4017164 0,62.8197793 0,62.8492031 C0,67.9542297 4.22727273,72 9.37416268,72 L58.8258373,72 C60.0421053,72 61.2435407,71.2496935 61.7033493,70.0433183 C62.1631579,68.8369432 61.8516746,67.498161 60.7985646,66.7478545 C58.1138756,65.0559869 57.9507177,61.3485901 60.338756,59.7008582 C60.8430622,59.2006539 61.9851675,58.1708214 61.8961722,56.6996322 C61.9703349,56.4642419 62,3.00122599 62,3.00122599 Z M6.05167464,62.8492031 C6.05167464,61.0543523 7.5645933,59.7008582 9.37416268,59.7008582 L52.9373206,59.7008582 C51.6023923,61.907642 51.8842105,64.496935 52.9373206,65.997548 L9.37416268,65.997548 C7.5645933,65.997548 6.05167464,64.6587658 6.05167464,62.8492031 Z M55.9631579,53.6984062 L9.38899522,53.6984062 C8.21722488,53.6984062 7.10478469,53.9190846 6.06650718,54.3163057 L6.06650718,11.4017164 C6.06650718,8.4004904 8.63253589,6.00245198 11.6583732,6.00245198 L55.9779904,6.00245198 L55.9779904,53.6984062 L55.9631579,53.6984062 Z" id="path-1"></path>
<filter x="-26.6%" y="-18.8%" width="153.2%" height="145.8%" filterUnits="objectBoundingBox" id="filter-2">
<feOffset dx="0" dy="3" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
</filter>
<polygon id="path-3" points="27.0340136 0 0 26.7240312 10.0272109 26.7240312 2.31972789 47 30 20.2742777 19.9710884 20.2742777"></polygon>
<filter x="-21.7%" y="-9.6%" width="150.0%" height="131.9%" filterUnits="objectBoundingBox" id="filter-4">
<feOffset dx="1" dy="3" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="2" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
</filter>
</defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="module">
<rect id="Rectangle" stroke="#979797" fill="#BA3434" x="0.5" y="0.5" width="255" height="255"></rect>
<circle id="Oval" fill="#E95252" cx="128" cy="85" r="57"></circle>
<g id="book-svgrepo-com" transform="translate(97.000000, 49.000000)" fill-rule="nonzero">
<g id="Shape">
<use fill="black" fill-opacity="1" filter="url(#filter-2)" xlink:href="#path-1"></use>
<use fill="#FFFFFF" xlink:href="#path-1"></use>
</g>
<g id="Path" transform="translate(16.000000, 6.000000)">
<use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-3"></use>
<use fill="#FFBC00" xlink:href="#path-3"></use>
</g>
</g>
<text id="Knowledge-Base-API" font-family="Helvetica" font-size="30" font-weight="normal" fill="#FFFFFF">
<tspan x="53.2763672" y="189">Knowledge</tspan>
<tspan x="65.7861328" y="225">Base API</tspan>
</text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View file

0
Resources/lang/.gitkeep Normal file
View file

0
Resources/views/.gitkeep Normal file
View file

24
composer.json Normal file
View file

@ -0,0 +1,24 @@
{
"name": "freescout/apiextender",
"description": "",
"authors": [
{
"name": "jtorvald",
"email": ""
}
],
"extra": {
"laravel": {
"providers": [
"Modules\\ApiExtender\\Providers\\ApiExtenderServiceProvider"
],
"aliases": {
}
}
},
"autoload": {
"psr-4": {
"Modules\\ApiExtender\\": ""
}
}
}

BIN
logo.sketch Normal file

Binary file not shown.

26
module.json Normal file
View file

@ -0,0 +1,26 @@
{
"name": "Api Extender",
"alias": "apiextender",
"description": "This module adds the a public API for categories and articles from the Knowledge base, report and other modules",
"version": "1.0.0",
"detailsUrl": "https://github.com/osoobe/freescout-api-extender",
"author": "osoobe",
"authorUrl": "https://github.com/osoobe",
"requiredAppVersion": "1.8.7",
"license": "MIT",
"keywords": [
"knowledge",
"api"
],
"img": "/modules/apiextender/images/module.svg",
"active": 0,
"order": 0,
"providers": [
"Modules\\ApiExtender\\Providers\\ApiExtenderServiceProvider"
],
"aliases": {},
"files": [
"start.php"
],
"requires": []
}

47
readme.md Normal file
View file

@ -0,0 +1,47 @@
# Knowledge base API module for FreeScout
This module adds the option to add a public API for the [FreeScout](https://freescout.net) knowledge base (module).

## Requirements
- [FreeScout](https://freescout.net) installed
- FreeScout [Knowledge base module](https://freescout.net/module/knowledge-base/)

## Installation

1. Download the latest module zip file via the releases card on the right.
2. Transfer the zip file to the server in the Modules folder of FreeScout.
3. Unpack the zip file.
4. Remove the zip file.
5. Activate the module via the Modules page in FreeScout.

## Update instructions

1. Download the latest module zip file via the releases card on the right.
2. Transfer the zip file to the server in the Modules folder of FreeScout.
3. Remove the folder ApiExtender
4. Unpack the zip file.
5. Remove the zip file.

## Contributing

Feel free to add your own features by sending a pull request.

## Get knowledge base categories in a mailbox

```
curl "https://example.com/api/knowledgebase/1/categories?locale=en" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json; charset=utf-8' \
-d $'{}'
```

## Get articles in a category

```
curl "https://example.com/api/knowledgebase/1/categories/1?locale=en" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json; charset=utf-8' \
-d $'{}'
```
## LICENSE

MIT

3
release.sh Normal file
View file

@ -0,0 +1,3 @@
#!/usr/bin/env sh
# rm ApiExtender-*.zip
# zip -r ApiExtender-1.0.1.zip ApiExtender -x "*.DS_Store" -x ".git*" -x ".idea*" -x "*.gitkeep"

17
start.php Normal file
View file

@ -0,0 +1,17 @@
<?php

/*
|--------------------------------------------------------------------------
| Register Namespaces And Routes
|--------------------------------------------------------------------------
|
| When a module starting, this file will execute automatically. This helps
| to register some namespaces like translator or view. Also, this file
| will load the routes file for each module. You may also modify
| this file as you want.
|
*/

if (!app()->routesAreCached()) {
require __DIR__ . '/Http/routes.php';
}