Skip to content

Commit 52bec5a

Browse files
author
extendy-sam
authored
Merge pull request #80 from Extendy/local-mshannaq-work
View URL Page
2 parents 16a7e81 + 7c3a08f commit 52bec5a

31 files changed

Lines changed: 1024 additions & 100 deletions

README.md

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,26 +29,21 @@ In addition to shortening URLs (based on domain that you use), SmartyURL also of
2929
* **Tracking and analytics**
3030
* **Customization**
3131

32-
## Server Requirements
32+
## Installation
3333

34-
- 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):
34+
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.
3535

36-
- [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)
37-
38-
- Your web hosting account should have MySQL 8.0+ support
36+
see [Developers Guide](docs/developers.md#installation) for more information about how to install SmartyURL.
3937

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

42-
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.
43-
44-
**Visitors IP Country detection**
45-
46-
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.
40+
## Documentation
4741

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

49-
## Documentation
44+
**Visitors IP Country detection**
5045

51-
Please take a look to SmartyURL [documentation](_docs/index.md) for detailed installation, configuration, and usage instructions.
46+
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.
5247

5348

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

6964
## SmartyURL Legal Notice
7065

71-
For more information, please refer to the [Legal Notice](_docs/legalnotice.md).
66+
For more information, please refer to the [Legal Notice](docs/legalnotice.md).

_docs/developers.md

Lines changed: 0 additions & 41 deletions
This file was deleted.

app/Config/AuthGroups.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ class AuthGroups extends ShieldAuthGroups
5858
'super.admin' => 'Does he super admin',
5959
'admin.manageotherurls' => 'can manage other users URLs', // not used yet
6060
// url
61-
'url.access' => 'Can Access URLs', // not used yet
61+
'url.access' => 'Can Access URLs',
6262
'url.new' => 'Can Create a new URL',
63-
'url.manage' => 'Can Manage URL (edit , delete)',
63+
'url.manage' => 'Can Manage his/her URLs only (edit , delete)',
6464
];
6565

6666
/**

app/Config/Routes.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
$routes->post('new', 'Url::newAction', ['filter' => 'session']);
2727
$routes->get('edit/(:num)', 'Url::edit/$1', ['filter' => 'session']);
2828
$routes->post('edit/(:num)', 'Url::editAction/$1', ['filter' => 'session']);
29+
$routes->get('hits/(:num)', 'Url::hitslist/$1', ['filter' => 'session']);
30+
$routes->get('qrcode/(:num)', 'Url::generateQRCode/$1', ['filter' => 'session']);
2931
});
3032

3133
// language route

app/Config/Smarty.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class Smarty extends BaseConfig
88
{
99
public $smarty_name = 'SmartyURL';
1010
public $smarty_online_repo = 'https://smartyurl.extendy.net';
11-
public $smarty_version = '0.0.0-dev-DND';
11+
public $smarty_version = '0.0.0-dev-DND-1';
1212

1313
/**
1414
* @var string contain the file name of jquery supported version eg jquery-3.7.1 without js

app/Config/Smartyurl.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,20 @@ class Smartyurl extends BaseConfig
8787
*/
8888
public int $maxUrlListPerPage = 100;
8989

90+
/**
91+
* QR code version depends on your specific requirements and use case.
92+
* QR codes come in various versions, ranging from Version 1 to Version 40
93+
* best from 3 to 10
94+
* default is 7 and if you have any error while generating QR Codes you can
95+
* increase it.
96+
* 7 can handle 528 bit (each utf-8 char is 8 bit)
97+
*
98+
* @see https://www.qrcode.com/en/about/version.html
99+
*
100+
* @var int
101+
*/
102+
public $qrCodeVersion = 7;
103+
90104
/**
91105
* The allowed pattern for Url Identifier
92106
*

app/Controllers/Assist.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,7 @@ function format(d) {
570570
"dom": 'lfrtipB',
571571
"processing": true,
572572
"serverSide": true,
573-
responsive: true,
573+
"responsive": true,
574574
order: [[0, 'desc']],
575575
"pageLength": {$defautltUrlListPerPage},
576576
"columnDefs": [

app/Controllers/Url.php

Lines changed: 165 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@
22

33
namespace App\Controllers;
44

5+
use App\Models\UrlHitsModel;
56
use App\Models\UrlModel;
67
use App\Models\UrlTagsDataModel;
78
use App\Models\UrlTagsModel;
9+
use chillerlan\QRCode\Output\QROutputInterface;
10+
use chillerlan\QRCode\QRCode;
11+
use chillerlan\QRCode\QROptions;
812
use Extendy\Smartyurl\SmartyUrl;
913
use Extendy\Smartyurl\UrlConditions;
1014
use Extendy\Smartyurl\UrlIdentifier;
@@ -25,6 +29,7 @@ public function __construct()
2529
$this->urltagsdatamodel = new UrlTagsDataModel();
2630
$this->urlmodel = new UrlModel();
2731
$this->urltags = new UrlTags();
32+
$this->urlhitsmodel = new UrlHitsModel();
2833
}
2934

3035
/**
@@ -236,7 +241,7 @@ public function listData()
236241
if ($result->url_title === '') {
237242
$urlTitle = lang('Url.UrlTitleNoTitle');
238243
} else {
239-
$urlTitle = $result->url_title;
244+
$urlTitle = esc($result->url_title);
240245
}
241246
// i will get the url tags
242247
$url_tags_json = $this->urltags->getUrlTagsCloud($result->url_id);
@@ -259,9 +264,9 @@ public function listData()
259264
} else {
260265
$url_owner = '';
261266
}
262-
267+
$result->url_identifier = esc($result->url_identifier);
263268
// $result->url_id],$result->url_title,$result->url_hitscounter
264-
$Go_Url = smarty_detect_site_shortlinker() . $result->url_identifier;
269+
$Go_Url = esc(smarty_detect_site_shortlinker() . $result->url_identifier);
265270
$records[] = [
266271
'url_id_col' => $result->url_id,
267272
'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>
@@ -291,7 +296,86 @@ public function listData()
291296

292297
public function view($UrlId)
293298
{
294-
d($UrlId);
299+
if (! auth()->user()->can('url.access', 'admin.manageotherurls', 'super.admin')) {
300+
return smarty_permission_error();
301+
}
302+
303+
$UrlModel = new UrlModel();
304+
$UrlTags = new UrlTags();
305+
$url_id = (int) esc(smarty_remove_whitespace_from_url_identifier($UrlId));
306+
if ($url_id === 0) {
307+
// url_id given is not valid id
308+
return redirect()->to('dashboard')->with('notice', lang('Url.urlError'));
309+
}
310+
$urlData = $UrlModel->where('url_id', $url_id)->first();
311+
312+
if ($urlData === null) {
313+
// url not exsists in dataase
314+
return redirect()->to('dashboard')->with('error', lang('Url.urlNotFoundShort'));
315+
}
316+
317+
// i will check the user permission , does he allowed to access this url info
318+
$userCanAccessUrl = $this->smartyurl->userCanAccessUrlInfo($url_id, (int) $urlData['url_user_id']);
319+
if (! $userCanAccessUrl) {
320+
return smarty_permission_error('It not your URL 😉😉😉');
321+
}
322+
$urlTagsCloud = $UrlTags->getUrlTagsCloud($url_id);
323+
// $urlTagsCloud = '[{"value":"tag1","tag_id":"3"},{"value":"tag2","tag_id":"27"},{"value":"tag3","tag_id":"24"}]';
324+
325+
$Go_Url = esc(smarty_detect_site_shortlinker() . $urlData['url_identifier']);
326+
$url_owner_username = smarty_get_user_username($urlData['url_user_id']);
327+
328+
$data = [];
329+
$data['url_id'] = $urlData['url_id'];
330+
if ($urlData['url_title'] === '') {
331+
$urlData['url_title'] = lang('Url.UrlTitleNoTitle');
332+
}
333+
$data['url_owner_username'] = $url_owner_username;
334+
$data['url_title'] = esc($urlData['url_title']);
335+
$data['url_targeturl'] = esc($urlData['url_targeturl']);
336+
$data['url_identifier'] = esc($urlData['url_identifier']);
337+
$data['url_hitscounter'] = $urlData['url_hitscounter'];
338+
339+
$data['created_at'] = $urlData['created_at'];
340+
$data['updated_at'] = $urlData['updated_at'];
341+
$data['go_url'] = $Go_Url;
342+
343+
$data['url_tags'] = json_decode($urlTagsCloud);
344+
345+
// i will get the redirect conditions
346+
$redirectConditions = json_decode($urlData['url_conditions']);
347+
$data['condition'] = null;
348+
$data['condition_text'] = null;
349+
350+
if ($redirectConditions !== null) {
351+
// there is a url redirect condition
352+
$data['condition'] = $redirectConditions->condition;
353+
354+
switch ($data['condition']) {
355+
case 'location':
356+
$data['condition_text'] = lang('Url.ByvisitorsGeolocation');
357+
break;
358+
359+
case 'device':
360+
$data['condition_text'] = lang('Url.ByvisitorsDevice');
361+
break;
362+
363+
default:
364+
$data['condition_text'] = $data['condition'];
365+
}
366+
367+
$data['conditions'] = $redirectConditions->conditions;
368+
} else {
369+
$data['condition_text'] = lang('Url.urlInfoNoRecdirectCondition');
370+
}
371+
372+
// dd($redirectConditions);
373+
374+
// i will try to get the last 25 hits of the url
375+
$lasthits = $this->urlhitsmodel->getLast25Hits($urlData['url_id']);
376+
$data['lasthits'] = $lasthits;
377+
378+
return view(smarty_view('url/urlinfo'), $data);
295379
}
296380

297381
public function new()
@@ -558,7 +642,7 @@ public function editAction($UrlId)
558642
}
559643

560644
// urlTitle
561-
$urlTitle = esc($this->request->getPost('UrlTitle'));
645+
$urlTitle = $this->request->getPost('UrlTitle');
562646
$redirectCondition = esc($this->request->getPost('redirectCondition'));
563647
if ($redirectCondition === 'device' || $redirectCondition === 'geolocation') {
564648
// url_conditions
@@ -643,10 +727,85 @@ public function editAction($UrlId)
643727
}
644728

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

649733
// updated error
650734
return redirect()->to("url/edit/{$UrlId}")->withInput()->with('error', lang('Url.UpdateURLError'));
651735
}
736+
737+
public function hitslist($UrlId)
738+
{
739+
echo 'URL HITS OF.' . $UrlId;
740+
}
741+
742+
public function generateQRCode($UrlId)
743+
{
744+
// set response type
745+
$response = service('response');
746+
$response->setContentType('image/svg+xml');
747+
748+
$error = '';
749+
if (! auth()->user()->can('url.access', 'admin.manageotherurls', 'super.admin')) {
750+
$error = 'Permission error';
751+
752+
return $response->setBody(smarty_svg_error($error));
753+
}
754+
755+
$UrlModel = new UrlModel();
756+
$url_id = (int) esc(smarty_remove_whitespace_from_url_identifier($UrlId));
757+
758+
if ($url_id === 0) {
759+
// url_id given is not valid id
760+
$error = lang('Url.urlError');
761+
762+
return $response->setBody(smarty_svg_error($error));
763+
}
764+
$urlData = $UrlModel->where('url_id', $url_id)->first();
765+
766+
if ($urlData === null) {
767+
// url not exsists in dataase
768+
$error = lang('Url.urlNotFoundShort');
769+
770+
return $response->setBody(smarty_svg_error($error));
771+
}
772+
773+
// i will check the user permission , does he allowed to access this url info
774+
$userCanAccessUrl = $this->smartyurl->userCanAccessUrlInfo($url_id, (int) $urlData['url_user_id']);
775+
if (! $userCanAccessUrl) {
776+
$error = 'not your URL 😉';
777+
778+
return $response->setBody(smarty_svg_error($error));
779+
}
780+
781+
$Go_Url = esc(smarty_detect_site_shortlinker() . $urlData['url_identifier']);
782+
783+
// prepare for the filename
784+
// remove any special chars and white spaces will be _
785+
$pattern = '/[^\w\d\.,;!?@#$%^&*()_+-=:<>"\'\/\\\[\]{}|`~]+/u';
786+
$filename = setting('Smartyurl.siteName') . "_{$UrlId}.svg";
787+
$filename = str_replace(' ', '_', $filename);
788+
$filename = preg_replace($pattern, '', $filename);
789+
790+
// if query download i will set Content Disposition to attachment
791+
$download = (int) $this->request->getGet('download'); // Access the 'download' parameter
792+
if ($download === 1) {
793+
$response->setHeader('Content-Disposition', 'attachment; filename="' . $filename . '"');
794+
} else {
795+
$response->setHeader('Content-Disposition', 'inline; filename="' . $filename . '"');
796+
}
797+
798+
// now I will generate QR Code
799+
$options = new QROptions();
800+
// i will smarty detect qr version by text length
801+
$options->version = smarty_smart_detect_qrversion($Go_Url);
802+
$options->outputType = QROutputInterface::MARKUP_SVG;
803+
$options->outputBase64 = false;
804+
$options->drawLightModules = true;
805+
$options->circleRadius = 0.4;
806+
$out = (new QRCode($options))->render($Go_Url);
807+
808+
// now i will return the image
809+
return $response->setBody($out);
810+
}
652811
}

app/Helpers/smarty_helper.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,3 +197,20 @@ function smarty_get_user_username($userId)
197197
return $username;
198198
}
199199
}
200+
201+
if (! function_exists('smarty_smart_detect_qrversion')) {
202+
function smarty_smart_detect_qrversion($url)
203+
{
204+
return setting('Smartyurl.qrCodeVersion');
205+
}
206+
}
207+
208+
if (! function_exists('smarty_svg_error')) {
209+
function smarty_svg_error($text)
210+
{
211+
return '<svg width="200" height="100" xmlns="http://www.w3.org/2000/svg">
212+
<rect width="100%" height="100%" fill="black" />
213+
<text x="50%" y="50%" fill="white" font-size="20" text-anchor="middle" alignment-baseline="middle">' . $text . '</text>
214+
</svg>';
215+
}
216+
}

app/Language/ar/Common.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?php
22

33
return [
4+
'javascriptNotEnabledNotice' => 'لقد تم تعطيل جافا سكربت في المتصفح او ان المتصفح لا يدعم جافاسكربت وبالتالي لن يعمل التطبيق بالشكل الامثل ، فعل جافا سكربت او استخدم متصفح يدعم جافا سكربت.',
45
'dashboardTitle' => 'صفحة المعلومات',
56
'dashboardLnk' => 'صفحة المعلومات',
67
'accountSettingsLnk' => 'اعدادات الحساب',

0 commit comments

Comments
 (0)