Skip to content

Commit

Permalink
Merge pull request #80 from Extendy/local-mshannaq-work
Browse files Browse the repository at this point in the history
View URL Page
  • Loading branch information
extendy-sam authored Nov 8, 2023
2 parents 16a7e81 + 7c3a08f commit 52bec5a
Show file tree
Hide file tree
Showing 31 changed files with 1,024 additions and 100 deletions.
23 changes: 9 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,26 +29,21 @@ In addition to shortening URLs (based on domain that you use), SmartyURL also of
* **Tracking and analytics**
* **Customization**

## Server Requirements
## Installation

- You need a web hosting account (for a domain or sub-domain) with PHP 7.4 or higher support and the following PHP extensions (typically supported by most PHP hosting providers):
Currently, as SmartyURL is in its early stages, you can only install it using Composer. Once we release the first official version of SmartyURL, we will offer detailed installation instructions for other methods.

- [mysqlnd](http://php.net/manual/en/mysqlnd.install.php) , [intl](http://php.net/manual/en/intl.requirements.php) , [mbstring](http://php.net/manual/en/mbstring.installation.php) , [libcurl](https://www.php.net/manual/en/curl.setup.php) , [gmp](https://www.php.net/manual/en/gmp.installation.php) , [json](https://www.php.net/manual/en/json.installation.php), [bcmath](https://www.php.net/manual/en/bc.setup.php)

- Your web hosting account should have MySQL 8.0+ support
see [Developers Guide](docs/developers.md#installation) for more information about how to install SmartyURL.

Afterwards, you can refer to the [installation instructions](_docs/installation.md) to set up the tool on your hosting account and begin using it.
Certainly, please refer to the [documentation](docs/index.md) for detailed instructions How configure, and effectively use SmartyURL for comprehensive guidance.

Certainly, please refer to the [documentation](_docs/index.md) for detailed instructions on how to install, configure, and effectively use Smart URL for comprehensive guidance.

**Visitors IP Country detection**

SmartyURL uses the `ip2location/ip2location-php` library to determine visitors country based on their IP addresses. It includes the free "IP2Location™ LITE IP-COUNTRY Database" for both personal and commercial use. For enhanced geographical redirect conditions with more accurate and up-to-date IP-based country data or if you need more accuracy consider purchasing a licensed IP2Location database. Refer to [IP2Location Database Docs](_docs/ip2location.md) for more details.
## Documentation

Please take a look to SmartyURL [documentation](docs/index.md) for detailed installation, configuration, and usage instructions.

## Documentation
**Visitors IP Country detection**

Please take a look to SmartyURL [documentation](_docs/index.md) for detailed installation, configuration, and usage instructions.
SmartyURL uses the `ip2location/ip2location-php` library to determine visitors country based on their IP addresses. It includes the free "IP2Location™ LITE IP-COUNTRY Database" for both personal and commercial use. For enhanced geographical redirect conditions with more accurate and up-to-date IP-based country data or if you need more accuracy consider purchasing a licensed IP2Location database. Refer to [IP2Location Database Docs](docs/ip2location.md) for more details.


## License
Expand All @@ -68,4 +63,4 @@ Also We would like to acknowledge the following resources and contributors for t

## SmartyURL Legal Notice

For more information, please refer to the [Legal Notice](_docs/legalnotice.md).
For more information, please refer to the [Legal Notice](docs/legalnotice.md).
41 changes: 0 additions & 41 deletions _docs/developers.md

This file was deleted.

4 changes: 2 additions & 2 deletions app/Config/AuthGroups.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ class AuthGroups extends ShieldAuthGroups
'super.admin' => 'Does he super admin',
'admin.manageotherurls' => 'can manage other users URLs', // not used yet
// url
'url.access' => 'Can Access URLs', // not used yet
'url.access' => 'Can Access URLs',
'url.new' => 'Can Create a new URL',
'url.manage' => 'Can Manage URL (edit , delete)',
'url.manage' => 'Can Manage his/her URLs only (edit , delete)',
];

/**
Expand Down
2 changes: 2 additions & 0 deletions app/Config/Routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
$routes->post('new', 'Url::newAction', ['filter' => 'session']);
$routes->get('edit/(:num)', 'Url::edit/$1', ['filter' => 'session']);
$routes->post('edit/(:num)', 'Url::editAction/$1', ['filter' => 'session']);
$routes->get('hits/(:num)', 'Url::hitslist/$1', ['filter' => 'session']);
$routes->get('qrcode/(:num)', 'Url::generateQRCode/$1', ['filter' => 'session']);
});

// language route
Expand Down
2 changes: 1 addition & 1 deletion app/Config/Smarty.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class Smarty extends BaseConfig
{
public $smarty_name = 'SmartyURL';
public $smarty_online_repo = 'https://smartyurl.extendy.net';
public $smarty_version = '0.0.0-dev-DND';
public $smarty_version = '0.0.0-dev-DND-1';

/**
* @var string contain the file name of jquery supported version eg jquery-3.7.1 without js
Expand Down
14 changes: 14 additions & 0 deletions app/Config/Smartyurl.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,20 @@ class Smartyurl extends BaseConfig
*/
public int $maxUrlListPerPage = 100;

/**
* QR code version depends on your specific requirements and use case.
* QR codes come in various versions, ranging from Version 1 to Version 40
* best from 3 to 10
* default is 7 and if you have any error while generating QR Codes you can
* increase it.
* 7 can handle 528 bit (each utf-8 char is 8 bit)
*
* @see https://www.qrcode.com/en/about/version.html
*
* @var int
*/
public $qrCodeVersion = 7;

/**
* The allowed pattern for Url Identifier
*
Expand Down
2 changes: 1 addition & 1 deletion app/Controllers/Assist.php
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,7 @@ function format(d) {
"dom": 'lfrtipB',
"processing": true,
"serverSide": true,
responsive: true,
"responsive": true,
order: [[0, 'desc']],
"pageLength": {$defautltUrlListPerPage},
"columnDefs": [
Expand Down
171 changes: 165 additions & 6 deletions app/Controllers/Url.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@

namespace App\Controllers;

use App\Models\UrlHitsModel;
use App\Models\UrlModel;
use App\Models\UrlTagsDataModel;
use App\Models\UrlTagsModel;
use chillerlan\QRCode\Output\QROutputInterface;
use chillerlan\QRCode\QRCode;
use chillerlan\QRCode\QROptions;
use Extendy\Smartyurl\SmartyUrl;
use Extendy\Smartyurl\UrlConditions;
use Extendy\Smartyurl\UrlIdentifier;
Expand All @@ -25,6 +29,7 @@ public function __construct()
$this->urltagsdatamodel = new UrlTagsDataModel();
$this->urlmodel = new UrlModel();
$this->urltags = new UrlTags();
$this->urlhitsmodel = new UrlHitsModel();
}

/**
Expand Down Expand Up @@ -236,7 +241,7 @@ public function listData()
if ($result->url_title === '') {
$urlTitle = lang('Url.UrlTitleNoTitle');
} else {
$urlTitle = $result->url_title;
$urlTitle = esc($result->url_title);
}
// i will get the url tags
$url_tags_json = $this->urltags->getUrlTagsCloud($result->url_id);
Expand All @@ -259,9 +264,9 @@ public function listData()
} else {
$url_owner = '';
}

$result->url_identifier = esc($result->url_identifier);
// $result->url_id],$result->url_title,$result->url_hitscounter
$Go_Url = smarty_detect_site_shortlinker() . $result->url_identifier;
$Go_Url = esc(smarty_detect_site_shortlinker() . $result->url_identifier);
$records[] = [
'url_id_col' => $result->url_id,
'url_identifier_col' => "<a class='link-dark listurls-link' href='" . site_url("url/view/{$result->url_id}") . "' data-url='{$Go_Url}'>{$result->url_identifier}</a>
Expand Down Expand Up @@ -291,7 +296,86 @@ public function listData()

public function view($UrlId)
{
d($UrlId);
if (! auth()->user()->can('url.access', 'admin.manageotherurls', 'super.admin')) {
return smarty_permission_error();
}

$UrlModel = new UrlModel();
$UrlTags = new UrlTags();
$url_id = (int) esc(smarty_remove_whitespace_from_url_identifier($UrlId));
if ($url_id === 0) {
// url_id given is not valid id
return redirect()->to('dashboard')->with('notice', lang('Url.urlError'));
}
$urlData = $UrlModel->where('url_id', $url_id)->first();

if ($urlData === null) {
// url not exsists in dataase
return redirect()->to('dashboard')->with('error', lang('Url.urlNotFoundShort'));
}

// i will check the user permission , does he allowed to access this url info
$userCanAccessUrl = $this->smartyurl->userCanAccessUrlInfo($url_id, (int) $urlData['url_user_id']);
if (! $userCanAccessUrl) {
return smarty_permission_error('It not your URL 😉😉😉');
}
$urlTagsCloud = $UrlTags->getUrlTagsCloud($url_id);
// $urlTagsCloud = '[{"value":"tag1","tag_id":"3"},{"value":"tag2","tag_id":"27"},{"value":"tag3","tag_id":"24"}]';

$Go_Url = esc(smarty_detect_site_shortlinker() . $urlData['url_identifier']);
$url_owner_username = smarty_get_user_username($urlData['url_user_id']);

$data = [];
$data['url_id'] = $urlData['url_id'];
if ($urlData['url_title'] === '') {
$urlData['url_title'] = lang('Url.UrlTitleNoTitle');
}
$data['url_owner_username'] = $url_owner_username;
$data['url_title'] = esc($urlData['url_title']);
$data['url_targeturl'] = esc($urlData['url_targeturl']);
$data['url_identifier'] = esc($urlData['url_identifier']);
$data['url_hitscounter'] = $urlData['url_hitscounter'];

$data['created_at'] = $urlData['created_at'];
$data['updated_at'] = $urlData['updated_at'];
$data['go_url'] = $Go_Url;

$data['url_tags'] = json_decode($urlTagsCloud);

// i will get the redirect conditions
$redirectConditions = json_decode($urlData['url_conditions']);
$data['condition'] = null;
$data['condition_text'] = null;

if ($redirectConditions !== null) {
// there is a url redirect condition
$data['condition'] = $redirectConditions->condition;

switch ($data['condition']) {
case 'location':
$data['condition_text'] = lang('Url.ByvisitorsGeolocation');
break;

case 'device':
$data['condition_text'] = lang('Url.ByvisitorsDevice');
break;

default:
$data['condition_text'] = $data['condition'];
}

$data['conditions'] = $redirectConditions->conditions;
} else {
$data['condition_text'] = lang('Url.urlInfoNoRecdirectCondition');
}

// dd($redirectConditions);

// i will try to get the last 25 hits of the url
$lasthits = $this->urlhitsmodel->getLast25Hits($urlData['url_id']);
$data['lasthits'] = $lasthits;

return view(smarty_view('url/urlinfo'), $data);
}

public function new()
Expand Down Expand Up @@ -558,7 +642,7 @@ public function editAction($UrlId)
}

// urlTitle
$urlTitle = esc($this->request->getPost('UrlTitle'));
$urlTitle = $this->request->getPost('UrlTitle');
$redirectCondition = esc($this->request->getPost('redirectCondition'));
if ($redirectCondition === 'device' || $redirectCondition === 'geolocation') {
// url_conditions
Expand Down Expand Up @@ -643,10 +727,85 @@ public function editAction($UrlId)
}

// return redirect()->to("url/edit/{$UrlId}")->withInput()->with('error', lang('OK'))->with('updated',"yes");
return redirect()->back()->with('success', lang('Url.UpdateURLOK'));
return redirect()->to("url/view/{$UrlId}")->with('success', lang('Url.UpdateURLOK'));
}

// updated error
return redirect()->to("url/edit/{$UrlId}")->withInput()->with('error', lang('Url.UpdateURLError'));
}

public function hitslist($UrlId)
{
echo 'URL HITS OF.' . $UrlId;
}

public function generateQRCode($UrlId)
{
// set response type
$response = service('response');
$response->setContentType('image/svg+xml');

$error = '';
if (! auth()->user()->can('url.access', 'admin.manageotherurls', 'super.admin')) {
$error = 'Permission error';

return $response->setBody(smarty_svg_error($error));
}

$UrlModel = new UrlModel();
$url_id = (int) esc(smarty_remove_whitespace_from_url_identifier($UrlId));

if ($url_id === 0) {
// url_id given is not valid id
$error = lang('Url.urlError');

return $response->setBody(smarty_svg_error($error));
}
$urlData = $UrlModel->where('url_id', $url_id)->first();

if ($urlData === null) {
// url not exsists in dataase
$error = lang('Url.urlNotFoundShort');

return $response->setBody(smarty_svg_error($error));
}

// i will check the user permission , does he allowed to access this url info
$userCanAccessUrl = $this->smartyurl->userCanAccessUrlInfo($url_id, (int) $urlData['url_user_id']);
if (! $userCanAccessUrl) {
$error = 'not your URL 😉';

return $response->setBody(smarty_svg_error($error));
}

$Go_Url = esc(smarty_detect_site_shortlinker() . $urlData['url_identifier']);

// prepare for the filename
// remove any special chars and white spaces will be _
$pattern = '/[^\w\d\.,;!?@#$%^&*()_+-=:<>"\'\/\\\[\]{}|`~]+/u';
$filename = setting('Smartyurl.siteName') . "_{$UrlId}.svg";
$filename = str_replace(' ', '_', $filename);
$filename = preg_replace($pattern, '', $filename);

// if query download i will set Content Disposition to attachment
$download = (int) $this->request->getGet('download'); // Access the 'download' parameter
if ($download === 1) {
$response->setHeader('Content-Disposition', 'attachment; filename="' . $filename . '"');
} else {
$response->setHeader('Content-Disposition', 'inline; filename="' . $filename . '"');
}

// now I will generate QR Code
$options = new QROptions();
// i will smarty detect qr version by text length
$options->version = smarty_smart_detect_qrversion($Go_Url);
$options->outputType = QROutputInterface::MARKUP_SVG;
$options->outputBase64 = false;
$options->drawLightModules = true;
$options->circleRadius = 0.4;
$out = (new QRCode($options))->render($Go_Url);

// now i will return the image
return $response->setBody($out);
}
}
17 changes: 17 additions & 0 deletions app/Helpers/smarty_helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,20 @@ function smarty_get_user_username($userId)
return $username;
}
}

if (! function_exists('smarty_smart_detect_qrversion')) {
function smarty_smart_detect_qrversion($url)
{
return setting('Smartyurl.qrCodeVersion');
}
}

if (! function_exists('smarty_svg_error')) {
function smarty_svg_error($text)
{
return '<svg width="200" height="100" xmlns="http://www.w3.org/2000/svg">
<rect width="100%" height="100%" fill="black" />
<text x="50%" y="50%" fill="white" font-size="20" text-anchor="middle" alignment-baseline="middle">' . $text . '</text>
</svg>';
}
}
1 change: 1 addition & 0 deletions app/Language/ar/Common.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

return [
'javascriptNotEnabledNotice' => 'لقد تم تعطيل جافا سكربت في المتصفح او ان المتصفح لا يدعم جافاسكربت وبالتالي لن يعمل التطبيق بالشكل الامثل ، فعل جافا سكربت او استخدم متصفح يدعم جافا سكربت.',
'dashboardTitle' => 'صفحة المعلومات',
'dashboardLnk' => 'صفحة المعلومات',
'accountSettingsLnk' => 'اعدادات الحساب',
Expand Down
Loading

0 comments on commit 52bec5a

Please sign in to comment.