Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/cydrobolt/polr.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChaoyi Zha <summermontreal@gmail.com>2018-04-21 04:35:45 +0300
committerGitHub <noreply@github.com>2018-04-21 04:35:45 +0300
commit1fb607ba631cf9a6c9eb7ed922bf723d2dfe03f3 (patch)
treec17e82a7b57bfca33836e7d5ffcb827d5e23999e
parentb29c5d51a92d44a712f300dd9c3e13e0a0945628 (diff)
Bulk link creation API (#443)
* Add bulk shortening API endpoint & create controller methods * Update documentation * Remove space %20 mapping for bulk API
-rw-r--r--app/Factories/LinkFactory.php5
-rw-r--r--app/Http/Controllers/Api/ApiLinkController.php79
-rw-r--r--app/Http/routes.php1
-rw-r--r--docs/developer-guide/api.md68
-rw-r--r--docs/developer-guide/api_errors.md2
-rw-r--r--docs/user-guide/installation.md6
6 files changed, 137 insertions, 24 deletions
diff --git a/app/Factories/LinkFactory.php b/app/Factories/LinkFactory.php
index 14e5463..7ff2bda 100644
--- a/app/Factories/LinkFactory.php
+++ b/app/Factories/LinkFactory.php
@@ -66,13 +66,13 @@ class LinkFactory {
// has custom ending
$ending_conforms = LinkHelper::validateEnding($custom_ending);
if (!$ending_conforms) {
- throw new \Exception('Sorry, but custom endings
+ throw new \Exception('Custom endings
can only contain alphanumeric characters, hyphens, and underscores.');
}
$ending_in_use = LinkHelper::linkExists($custom_ending);
if ($ending_in_use) {
- throw new \Exception('Sorry, but this URL ending is already in use.');
+ throw new \Exception('This URL ending is already in use.');
}
$link_ending = $custom_ending;
@@ -97,7 +97,6 @@ class LinkFactory {
$link->is_api = $is_api;
if ($creator) {
- // if user is logged in, save user as creator
$link->creator = $creator;
}
diff --git a/app/Http/Controllers/Api/ApiLinkController.php b/app/Http/Controllers/Api/ApiLinkController.php
index e05c25e..b1f377c 100644
--- a/app/Http/Controllers/Api/ApiLinkController.php
+++ b/app/Http/Controllers/Api/ApiLinkController.php
@@ -7,12 +7,22 @@ use App\Helpers\LinkHelper;
use App\Exceptions\Api\ApiException;
class ApiLinkController extends ApiController {
+ protected function getShortenedLink($long_url, $is_secret, $custom_ending, $link_ip, $username, $response_type) {
+ try {
+ $formatted_link = LinkFactory::createLink(
+ $long_url, $is_secret, $custom_ending, $link_ip, $username, false, true);
+ }
+ catch (\Exception $e) {
+ throw new ApiException('CREATION_ERROR', $e->getMessage(), 400, $response_type);
+ }
+
+ return $formatted_link;
+ }
+
public function shortenLink(Request $request) {
$response_type = $request->input('response_type');
$user = $request->user;
- // Validate parameters
- // Encode spaces as %20 to avoid validator conflicts
$validator = \Validator::make(array_merge([
'url' => str_replace(' ', '%20', $request->input('url'))
], $request->except('url')), [
@@ -23,20 +33,69 @@ class ApiLinkController extends ApiController {
throw new ApiException('MISSING_PARAMETERS', 'Invalid or missing parameters.', 400, $response_type);
}
- $long_url = $request->input('url'); // * required
- $is_secret = ($request->input('is_secret') == 'true' ? true : false);
+ $formatted_link = $this->getShortenedLink(
+ $request->input('url'),
+ ($request->input('is_secret') == 'true' ? true : false),
+ $request->input('custom_ending'),
+ $request->ip(),
+ $user->username,
+ $response_type
+ );
+
+ return self::encodeResponse($formatted_link, 'shorten', $response_type);
+ }
+
+ public function shortenLinksBulk(Request $request) {
+ $response_type = $request->input('response_type', 'json');
+ $request_data = $request->input('data');
+ $user = $request->user;
$link_ip = $request->ip();
- $custom_ending = $request->input('custom_ending');
+ $username = $user->username;
- try {
- $formatted_link = LinkFactory::createLink($long_url, $is_secret, $custom_ending, $link_ip, $user->username, false, true);
+ if ($response_type != 'json') {
+ throw new ApiException('JSON_ONLY', 'Only JSON-encoded responses are available for this endpoint.', 401, $response_type);
}
- catch (\Exception $e) {
- throw new ApiException('CREATION_ERROR', $e->getMessage(), 400, $response_type);
+
+ $links_array_raw_json = json_decode($request_data, true);
+
+ if ($links_array_raw_json === null) {
+ throw new ApiException('INVALID_PARAMETERS', 'Invalid JSON.', 400, $response_type);
}
- return self::encodeResponse($formatted_link, 'shorten', $response_type);
+ $links_array = $links_array_raw_json['links'];
+
+ foreach ($links_array as $link) {
+ $validator = \Validator::make($link, [
+ 'url' => 'required|url'
+ ]);
+
+ if ($validator->fails()) {
+ throw new ApiException('MISSING_PARAMETERS', 'Invalid or missing parameters.', 400, $response_type);
+ }
+ }
+
+ $formatted_links = [];
+
+ foreach ($links_array as $link) {
+ $formatted_link = $this->getShortenedLink(
+ $link['url'],
+ (array_get($link, 'is_secret') == 'true' ? true : false),
+ array_get($link, 'custom_ending'),
+ $link_ip,
+ $username,
+ $response_type
+ );
+
+ $formatted_links[] = [
+ 'long_url' => $link['url'],
+ 'short_url' => $formatted_link
+ ];
+ }
+
+ return self::encodeResponse([
+ 'shortened_links' => $formatted_links
+ ], 'shorten_bulk', 'json');
}
public function lookupLink(Request $request) {
diff --git a/app/Http/routes.php b/app/Http/routes.php
index 7982af5..e936cb1 100644
--- a/app/Http/routes.php
+++ b/app/Http/routes.php
@@ -66,6 +66,7 @@ $app->group(['prefix' => '/api/v2', 'namespace' => 'App\Http\Controllers\Api', '
/* API shorten endpoints */
$app->post('action/shorten', ['as' => 'api_shorten_url', 'uses' => 'ApiLinkController@shortenLink']);
$app->get('action/shorten', ['as' => 'api_shorten_url', 'uses' => 'ApiLinkController@shortenLink']);
+ $app->post('action/shorten_bulk', ['as' => 'api_shorten_url_bulk', 'uses' => 'ApiLinkController@shortenLinksBulk']);
/* API lookup endpoints */
$app->post('action/lookup', ['as' => 'api_lookup_url', 'uses' => 'ApiLinkController@lookupLink']);
diff --git a/docs/developer-guide/api.md b/docs/developer-guide/api.md
index b0edd90..bcd1927 100644
--- a/docs/developer-guide/api.md
+++ b/docs/developer-guide/api.md
@@ -2,8 +2,8 @@
-----------------------------
## API keys
-To authenticate a user to Polr, you will need to provide an API key along with
-each request to the Polr API, as a GET or POST parameter. (e.g `?key=API_KEY_HERE`)
+To authenticate a user to Polr, you *must* provide an API key along with
+each request to Polr API endpoints, as a GET or POST parameter. (e.g `?key=API_KEY_HERE`)
## Assigning an API key
To assign an API key, log on from an administrator account, head over to the "Admin"
@@ -26,11 +26,9 @@ See [API endpoints](#api-endpoints) for more information on the actions.
## Response Type
The Polr API will reply in `plain_text` or `json`. The response type can be
-set by providing the `response_type` argument to the request. If not provided,
-the response type will default to `plain_text`.
-
-Data endpoints will only return JSON-formatted data and will default to `json` if no
-`response_type` is provided.
+set by providing the `response_type` argument to the request. If this argument is not provided,
+the response type will default to either `plain_text` or `json` depending
+on the endpoint.
Example `json` responses:
```
@@ -84,7 +82,61 @@ Response:
}
```
-Remember that the `url` argument must be URL encoded.
+The `url` argument must be URL encoded.
+
+### /api/v2/action/shorten_bulk
+
+_`POST` only_
+
+Arguments:
+
+ - `data`: a string containing a JSON-encoded object with an array of links
+
+Example `data` argument:
+```json
+{
+ "links": [
+ {
+ "url": "https://polrproject.org/"
+ },
+ {
+ "url": "https://youtube.com",
+ "is_secret": true
+ },
+ {
+ "url": "https://github.com/cydrobolt/polr",
+ "custom_ending": "polrgithub"
+ }
+ ]
+}
+```
+
+Response: A JSON-encoded object with a list of shortened links.
+
+Example response:
+```
+{
+ "action": "shorten_bulk",
+ "result": {
+ "shortened_links": [
+ {
+ "long_url": "https://polrproject.org/",
+ "short_url": "http://demo.polr.me/81"
+ },
+ {
+ "long_url": "https://youtube.com",
+ "short_url": "http://demo.polr.me/84/b496"
+ },
+ {
+ "long_url": "https://github.com/cydrobolt/polr",
+ "short_url": "http://demo.polr.me/polrgithub"
+ }
+ ]
+ }
+}
+```
+
+
### /api/v2/action/lookup
The `lookup` action takes a single argument: `url_ending`. This is the URL to
diff --git a/docs/developer-guide/api_errors.md b/docs/developer-guide/api_errors.md
index adbe5e8..7346b66 100644
--- a/docs/developer-guide/api_errors.md
+++ b/docs/developer-guide/api_errors.md
@@ -8,6 +8,8 @@ it to `true` in `.env`
`MISSING_PARAMETERS`: Invalid or missing parameters.
+`INVALID_PARAMETERS`: Invalid parameters.
+
`NOT_FOUND`: Object not found.
`ACCESS_DENIED`: User is not authorized to access the object.
diff --git a/docs/user-guide/installation.md b/docs/user-guide/installation.md
index f97a930..96feef9 100644
--- a/docs/user-guide/installation.md
+++ b/docs/user-guide/installation.md
@@ -23,7 +23,7 @@ you may be interested in looking at a [legacy 1.x release](https://github.com/cy
- JSON PHP Extension
- PHP curl extension
-## Downloading the source code
+## Download the source code
If you would like to download a stable version of Polr, you may check out [the releases page](https://github.com/cydrobolt/polr/releases).
@@ -49,7 +49,7 @@ $ chown -R apache polr
$ chcon -R -t httpd_sys_rw_content_t polr/storage polr/.env
```
-## Installing using `composer`
+## Install `composer` dependencies
```bash
# download composer package
@@ -177,7 +177,7 @@ server {
To run Polr on another HTTP server or on shared hosting, you will need to set the home
directory to `/PATH_TO_POLR/public`, not the root Polr folder.
-## Creating the database
+## Create the database
### MySQL