Compare commits

...

5 Commits

Author SHA1 Message Date
Supan Adit Pratama
7456516eac fix: ssl issue for production use 2022-09-08 23:37:03 +07:00
Supan Adit Pratama
70fa9caf7a feat: docker usage for development 2022-05-02 21:30:06 +07:00
Supan Adit Pratama
a0f995d00a feat: add docker support 2022-02-06 14:45:02 +07:00
Supan Adit Pratama
f5318a6942 Beautify code 2021-02-14 01:07:46 +07:00
Supan Adit Pratama
bc6e86d717 Add demo image 2020-12-12 21:25:42 +07:00
20 changed files with 549 additions and 613 deletions

24
.dockerignore Normal file
View File

@ -0,0 +1,24 @@
.github/
.idea/
.vscode/
tests
docker-compose.dev.yml
docker-compose.yml
.dockerignore
.editorconfig
.gitattributes
.gitignore
.styleci.yml
vendor
Dockerfile
PHP.Dockerfile
phpunit.xml
README.md
mysql

39
.env.docker Executable file
View File

@ -0,0 +1,39 @@
APP_NAME=Laravel
APP_ENV=production
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost
LOG_CHANNEL=stack
BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=null
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

15
.gitignore vendored
View File

@ -1,8 +1,8 @@
/node_modules
/public/hot
/public/storage
/storage/*.key
/vendor
node_modules/
public/hot/
public/storage/
storage/*.key/
vendor/
.env
.env.backup
.phpunit.result.cache
@ -11,4 +11,7 @@ Homestead.yaml
npm-debug.log
yarn-error.log
.idea
.idea/
.vscode/
mysql/

30
Dockerfile Normal file
View File

@ -0,0 +1,30 @@
FROM php:7.4-apache
RUN apt-get update
RUN apt-get install -y git zip
# Set Apache Root
ENV APACHE_DOCUMENT_ROOT=/var/www/html/public
RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf
RUN sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf
# Enable Some Apache Mod
RUN a2enmod rewrite headers
RUN docker-php-ext-install pdo pdo_mysql
# Composer
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
# Copy Source Code
COPY .env.docker /var/www/html/.env
COPY . /var/www/html
# Change Working Directory
WORKDIR /var/www/html
# Composer install and generate key
RUN composer install && php artisan key:generate
RUN chown -R www-data:www-data /var/www/html

16
PHP.Dockerfile Normal file
View File

@ -0,0 +1,16 @@
FROM php:7.4-cli
RUN apt-get update
RUN apt-get install -y git zip
RUN docker-php-ext-install pdo pdo_mysql
RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
# Composer
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
WORKDIR /short
CMD [ "php", "artisan","serve" ,"--host","0.0.0.0"]

107
README.md
View File

@ -3,15 +3,26 @@
This is url shortener application is similar to [bit.ly](http://bit.ly)
## Demo
- Host : https://short.supanadit.com
- Email : admin@email.com
- Password : 123
### Generate Short URL
![Demo 1](demo/demo-1.gif)
### Generate Protected Short URL
![Demo 2](demo/demo-2.gif)
## Requirements
- Laravel 7.0+
- PHP 7.4
## Quick Start
- `composer install`
- create `.env` file
- `php artisan key:generate`
@ -20,6 +31,7 @@ This is url shortener application is similar to [bit.ly](http://bit.ly)
- `php artisan serve`
#### Apache Configuration for Virtual Host
```apacheconfig
<VirtualHost *:80>
DocumentRoot /srv/http/short/public
@ -39,17 +51,108 @@ This is url shortener application is similar to [bit.ly](http://bit.ly)
</VirtualHost>
```
## Docker Way
This app can run inside docker with official support
### Via Docker Compose
```bash
docker-compose up -d
```
### Run Migration
```bash
docker-compose exec short-app php artisan migrate
```
### Run Seeder
```bash
docker-compose exec short-app php artisan db:seed
```
### Build Docker By Yourself
```bash
docker build . -t supanadit/short-url:1.0.2
```
## Development Using Docker
### Run Application
```bash
docker-compose -f docker-compose.dev.yml up -d
```
### Installing / Updating Dependencies
```bash
docker-compose -f docker-compose.dev.yml exec -w /srv short composer install # Composer Install
```
### Generate Key
```bash
docker-compose -f docker-compose.dev.yml exec -w /srv short php artisan key:generate # Generate Key
```
### Database Migration
```bash
docker-compose -f docker-compose.dev.yml exec -w /srv short php artisan migrate
```
### Database Seed
```bash
docker-compose -f docker-compose.dev.yml exec -w /srv short php artisan db:seed
```
### Shutdown Application
```bash
docker-compose -f docker-compose.dev.yml down
```
### Updating `.env`
```bash
docker-compose -f docker-compose.dev.yml exec -w /srv short php artisan config:cache
```
### Rebuilding Dockerfile
```bash
docker-compose -f docker-compose.dev.yml build
```
### Troubleshooting MySQL Won't Run In Docker
Run this script `sudo chown -R 1001:1001 mysql`
Because we used Bitnami distribution version of MySQL, so we need to change the permission of mysql folder, since it
also described in docker page of bitnami
## Note
If you want to use forgot password feature, you must provide your email and password at `.env`
## Support
[![ko-fi](https://www.ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/N4N01CIMZ)
## License
Copyright 2020 Supan Adit Pratama
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "
AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
language governing permissions and limitations under the License.

View File

@ -100,7 +100,7 @@ class UrlShortenerController extends Controller
$url = $urlAddress->url_destination;
if ($httpPath == substr($url, 0, strlen($httpPath))) {
$hasHttpOrHttps = true;
} else if ($httpsPath == substr($url, 0, strlen($httpsPath))) {
} elseif ($httpsPath == substr($url, 0, strlen($httpsPath))) {
$hasHttpOrHttps = true;
}
@ -145,7 +145,7 @@ class UrlShortenerController extends Controller
$url = $urlAddress->url_destination;
if ($httpPath == substr($url, 0, strlen($httpPath))) {
$hasHttpOrHttps = true;
} else if ($httpsPath == substr($url, 0, strlen($httpsPath))) {
} elseif ($httpsPath == substr($url, 0, strlen($httpsPath))) {
$hasHttpOrHttps = true;
}

View File

@ -12,7 +12,7 @@ class TrustProxies extends Middleware
*
* @var array|string|null
*/
protected $proxies;
protected $proxies = "*";
/**
* The headers that should be used to detect proxies.

View File

@ -3,6 +3,7 @@
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\URL;
class AppServiceProvider extends ServiceProvider
{
@ -23,6 +24,8 @@ class AppServiceProvider extends ServiceProvider
*/
public function boot()
{
//
if (config('app.env') == 'production') {
URL::forceScheme('https');
}
}
}

BIN
demo/demo-1.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 MiB

BIN
demo/demo-2.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 MiB

20
docker-compose.dev.yml Normal file
View File

@ -0,0 +1,20 @@
version: "3.8"
services:
todo:
build:
context: .
dockerfile: PHP.Dockerfile
ports:
- "8000:8000"
volumes:
- "./:/short"
mysqldb:
image: "bitnami/mysql:8.0"
ports:
- "3306:3306"
volumes:
- "./mysql:/bitnami/mysql/data"
environment:
- MYSQL_ROOT_PASSWORD=secret
- MYSQL_DATABASE=short

27
docker-compose.yml Normal file
View File

@ -0,0 +1,27 @@
version: "2"
services:
mysql:
image: "bitnami/mysql:8.0"
ports:
- "3306:3306"
volumes:
- "./mysql:/bitnami/mysql/data"
environment:
- MYSQL_ROOT_PASSWORD=secret
- MYSQL_DATABASE=short
short-app:
build:
context: .
dockerfile: Dockerfile
ports:
- "80:80"
environment:
- DB_CONNECTION=mysql
- DB_HOST=mysql
- DB_PORT=3306
- DB_DATABASE=short
- DB_USERNAME=root
- DB_PASSWORD=secret
depends_on:
- mysql

View File

@ -1,324 +0,0 @@
jQuery Sparkline Plugin ChangeLog
http://omnipotent.net/jquery.sparkline/
2.1.x ???
+ Fix for IE <= 9 for loading CSS when 31 stylesheets are already present
2.1.2 15/June/2013
+ Make compatible with jQuery 1.10
+ Fix intermittent "undefined error" with IE8 (issue 64)
Thanks Tim Tucker
+ Performance/minification size improvement (PR 34)
Thanks Tim Tucker
+ Prevent the plugin from being instatiated more than once (PR 37)
Thanks Tim Tucker
2.1.1 26/January/2013
+ Fix a couple of issues rendering pie charts in IE when they slices that make
up a negligible percentage of the whole chart (issue 49)
+ Don't display line chart final marker if final value is null (issue 46)
+ Make compatible with jQuery 1.9.0 (issue 60)
2.1 15/October/2012
+ Added support for Internet Explorer 10 (issue 18)
Thanks Jonathan Sampson
+ Enable the plugin to be loaded dynamically (issue 6)
Thanks joeenzminger
+ Pie charts with zero in the array of values will no longer
cause IE to display "undefined" in the page (issue 9)
+ Null values in bar charts are now correctly omitted by default (issue 23)
+ Null values in line charts would cause value highligting to be
incorrect (issue 4)
+ Raise default z-index for tooltips to ensure they always appear on top
of the chart (issue 5)
+ Allow target and performance values to be set to null for bullet charts,
omitting them from the chart (issue 3)
+ Fix clipping of highlight marker spots if min/max/final spots are disabled
in line charts (issue 31)
+ Line charts with normalRangeMin=0 will now render the normal range
correctly (issue 7)
Thanks Tim Mathewso
+ Add support for AMD based module loaders such as requirejs (PR 32)
Thanks Tim Tucker
+ Fix interquartile range calculation used by box plots (PR 10)
Thanks Claudio Riva
2.0 29/April/2012
+ jQuery.sparkline now requires jQuery 1.4.3 or later
+ All charts now support mouseover and click actions
Adds options: disableInteraction, disableTooltips, disableHighlight
+ Added sparklineClick and sparklineRegionChange events
+ Line charts have highlightSpotColor and highlightLineColor options
for controlling mouseover highligiting
+ All charts display tooltips and highlight values when moused-over by default
Adds options: tooltipContainer, tooltipOffsetX, tooltipOffsetY, tooltipFormatter,
tooltipChartTitle, tooltipFormat, tooltipPrefix, tooltipSuffix,
tooltipSkipNull, tooltipValueLookups, highlightLighten, numberFormatter,
numberDigitGroupSep, numberDecimalMark, numberDigitGroupCount
+ Fix error when all null values are fed to a line chart
Thanks Ton Voon
+ Fix off-by-one error that caused the bottom of filled line charts to
be unlevel - Thanks Sylvain Vieujot for the bug report
+ Pie charts with a single value now render correctly
Thanks Juan Manuel
+ Charts that have their dimensions specified exactly in pixels may see
improved performance
Thanks Sean Carpenter
+ Coloured spots may be added to some or all values on a line chart now using
the new valueSpots option
Thanks Russ Beebe for the suggestion
+ Bar and tristates charts now support using range of values for the colorMap
option - Eg. allows all bars with values betweeen 10 and 20 to be green
+ Pie charts may now have a border using the borderWidth and borderColor
options - Thanks Michael Mior for the suggestion
+ Added a disableHiddenCheck option - If you know your charts will never be
in a hidden block (display:none) at time of rendering, disabling this check
may improve performance
+ Reduce number of DOM interactions when rendering charts in Internet Explorer
to increase render performance
+ Bar charts may now have stacked values by providing an array of arrays
or by passing a comma and colon delimited series of values (eg. "1:2:3,2:3:1")
+ Fix a bug where some spots would be drawn in the wrong position on line
charts if the x values were supplied as well as the y
+ Fix a bug causing hidden composite sparklines to fail to render
once $.sparkline_display_visible() is called.
+ If there are multiple calls to sparkline() on a hidden element, the plugin
will now only render the most recent one when the element becomes visible,
saving CPU time for the same visual result.
+ If a hidden sparkline waiting to be rendered is removed from the DOM
via jQuery's .remove() or .html() etc methods then it will be
removed from the pending queue the next time $.sparkline_display_visible()
is called, preventing a memory leak.
+ Add the $.range_map() and $.spformat() methods
1.6 30/November/2010
+ Allow options to be set as tag attributes, as well as passed in to the sparkline
function as an argument. See new enableTagOptions and tagOptionPrefix options.
+ Added alternate methods of passing values in via HTML.
Can now include inline values in a comment, or pass values in as a values
attribute on the tag:
<span class="sparkline"><!-- 1,2,3,4,5 --></span>
<span class="sparkline" values="1,2,3,4,5"></span>
+ bullet graphs now handle non-integer values correctly
+ Added drawNormalOnTop option to line charts to force the normal
range to be drawn over the top of the line chart's fill color
+ Detect if an element is not inserted into the DOM so that $.sparkline_display_visible()
will function correctly after it's later inserted.
+ Remove the use of the Array indexOf prototype that was added to IE to avoid
conflicts with other libraries.
+ Default settings are now exposed as $.fn.sparkline.defaults allowing
script-wide changes to be made instead of passing them to the sparkline function
on each call
1.5.1 01/March/2010
+ 1 character typo fix for IE - Thanks to Daniel Kenyon-Jones for the heads up
1.5 26/February/2010
+ Very small pie slices could fill the whole chart in IE
Thanks to Peter Doel for catching and fixing it
+ Added chartRangeClip option to force values outside of chartRangeMin/chartRangeMax
to be clipped
+ Added chartRangeMinX/chartRangeMaxX for line charts
+ Allow chart types other than line chart to be used as composites.
+ colorMap may now pass null as a colour to omit that bar from display entirely
+ colorMap may now be passed as an Array of values allowing the colour of each
bar to be specified individually, rather than mapping by value
+ Added nullColor option to bar charts to force null values to show up as a thin line
+ Performance improvements with IE
1.4.3 14/September/2009
+ Updated default pie chart colours - Thanks Liel Dulev
+ Null values can now be supplied to line and bar charts
(use 'null' as the value) - Thanks to Ed Blachman for
testing/debugging help
+ Added colorMap option for bar charts
+ Added lineWidth option for line charts - Can be an integer or a float
(try 1.5 or 2)
1.4.2 25/April/2009
+ Fixed rendering of circular spots on line charts
for Internet Explorer 8
1.4.1 27/March/2009
+ Fixed minor off-by-1-pixel display glitch with IE
+ Improved compatibilty with jQuery 1.3 which could cause some sparklines
not to be rendered in certain situations
1.4 25/February/2009
+ Added the box plot chart type
+ Fixed a canvas rendering issue that would display some charts with
fuzzy lines
+ Fixed error in bar charts which would causes bars to be too short.
+ Couple of other minor bug fixes
1.3 25/January/2009
+ Sparklines can't be automatically displayed into hidden elements (ie.
with display:none) - Added a $.sparkline_display_visible() function
to render any sparklines that were generated while a tag was
hidden
+ Fixed positioning issues where sparklines would be displayed a few
pixels offset from their containers in some browsers
+ Made a first attempt at IE8 support. IE8 beta 2 seems to
have some vml related bugs though so having more than one sparkline
on a line doesn't work correctly, nor do the markers on line charts
+ Misc other bug fixes
+ Updated the web site with a new look
1.2.1 24/November/2008
+ Pie chart bug fixes: Divide by zero error resolved
and IE rendering issue if a pie slice is equal to 0
Thanks to Hubert Mandeville for a patch fixing both issues
1.2 - 19/November/2008
+ Fixed positioning of min/max line markers for fixed range graphs
(thanks to Stéphane Busso)
+ Fixed rendering of bar charts with negative values
+ All values in a bar chart have a height now (min values used to
have height = 0)
+ Added zeroColor option for bar charts which allows assignment of
a different color for values that are equal to zero
+ Line charts can now specify both x and y values if required in one of
three ways:
a) Inline with HTML with values interleaved:
x1:y1,x2:y2,x3:y3
eg. <span class="linechart">1:10,5:8,7:10</span>
b) Programatically using an x,y array for each value:
$('#mychart').sparkline([ [1,10], [5,8], [7,10] ]);
c) Programatically using a separate array for the x values:
$('#mychart').sparkline( [10,8,10], { xvalues: [1,5,7] });
+ Added chartRangeMin and chartRangeMax to line, bar and discrete graphs
This allows you to artificialy fix the min/max values for the graph
so that multiple graphs can share the same scale.
+ Added defaultPixelsPerValue option to specify how many pixels wide
each value should be in a dynamically sized line graph
+ Added offset option to piecharts - Takes a positive or negative degree
offset to start drawing the chart from.
1.1 - 29/July/2008
+ Added minSpotColor and maxSpotColor to line charts - If set then spot
markers are placed at the cordinates of the minimum and maximum values.
+ Added normalRangeMin and normalRangeMax to line charts - If set then
a normalRangeColor band will be drawn on the graph
+ Added chart compositing - Applying another chart to a DOM element with
an option of composite: true will cause the second (or more) chart to be
overlayed on the first rather than replacing it.
+ Added optional colorMap option to tristate chart - This allows specific
colors to be supplied for specific values
+ Added discrete chart type - Uses fixed size discrete vertical lines to mark
each values in a series
+ Added bullet graph type - Implementation of Stephen Few's bullet graphs
+ Added pie chart type
+ Improved auto height option to match the line height of the containing
element
+ Fixed some off by one positioning errors
+ Reduced the default radius of spot markers from 2 to 1.5 pixels
1.0 - 17/July/2008
+ Initial Release

View File

@ -1,11 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="csrf_token" content="{{ csrf_token() }}"/>
<meta name="csrf_token" content="{{ csrf_token() }}" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Short URL</title>
<link rel="shortcut icon" href="{{asset('favicon.png')}}"/>
<link rel="shortcut icon" href="{{asset('favicon.png')}}" />
<!-- Tell the browser to be responsive to screen width -->
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<!-- Bootstrap 3.3.7 -->
@ -30,52 +31,49 @@
<!-- Google Font -->
<link rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic">
href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic">
</head>
<body class="hold-transition login-page">
<div class="login-box">
<div class="login-logo">
<a href="/"><b>Short</b>&nbsp;URL</a>
</div>
<!-- /.login-logo -->
<div class="login-box-body">
<p class="login-box-msg">Expired</p>
<p>
I am sorry, the link is expired, so please just back to the homepage, or if you own the link just regenerate
the link, but if you get the link from somebody just ask to the person who share this link.
</p>
<div class="input-group">
<input type="text"
class="form-control"
placeholder="Generated URL"
id="generated-url-field"
value="{{$url}}"
readonly>
<span class="input-group-btn">
<button type="button" class="btn btn-danger btn-flat"
data-clipboard-target="#generated-url-field">
<i class="fa fa-clipboard"></i>
</button>
</span>
<div class="login-box">
<div class="login-logo">
<a href="/"><b>Short</b>&nbsp;URL</a>
</div>
<!-- /.login-logo -->
<div class="login-box-body">
<p class="login-box-msg">Expired</p>
<p>
I am sorry, the link is expired, so please just back to the homepage, or if you own the link just
regenerate
the link, but if you get the link from somebody just ask to the person who share this link.
</p>
<div class="input-group">
<input type="text" class="form-control" placeholder="Generated URL" id="generated-url-field"
value="{{$url}}" readonly>
<span class="input-group-btn">
<button type="button" class="btn btn-danger btn-flat" data-clipboard-target="#generated-url-field">
<i class="fa fa-clipboard"></i>
</button>
</span>
</div>
</div>
<!-- /.login-box-body -->
</div>
<!-- /.login-box-body -->
</div>
<!-- /.login-box -->
<!-- /.login-box -->
<!-- jQuery 3 -->
<script src="{{asset('vendor/jquery/dist/jquery.min.js')}}"></script>
<!-- Bootstrap 3.3.7 -->
<script src="{{asset('vendor/bootstrap/dist/js/bootstrap.min.js')}}"></script>
<!-- Toastr -->
<script src="{{asset('vendor/toastr/toastr.min.js')}}"></script>
<!-- Clipboard -->
<script src="{{asset('vendor/clipboard.js/dist/clipboard.min.js')}}"></script>
<!-- iCheck -->
<script src="{{asset('plugin/iCheck/icheck.min.js')}}"></script>
<!-- jQuery 3 -->
<script src="{{asset('vendor/jquery/dist/jquery.min.js')}}"></script>
<!-- Bootstrap 3.3.7 -->
<script src="{{asset('vendor/bootstrap/dist/js/bootstrap.min.js')}}"></script>
<!-- Toastr -->
<script src="{{asset('vendor/toastr/toastr.min.js')}}"></script>
<!-- Clipboard -->
<script src="{{asset('vendor/clipboard.js/dist/clipboard.min.js')}}"></script>
<!-- iCheck -->
<script src="{{asset('plugin/iCheck/icheck.min.js')}}"></script>
<script type="application/javascript">
const clipboard = new ClipboardJS('.btn');
<script type="application/javascript">
const clipboard = new ClipboardJS('.btn');
clipboard.on('success', function (e) {
toastr.success("URL Copied");
e.clearSelection();
@ -84,6 +82,7 @@
clipboard.on('error', function (e) {
toastr.failed("Cannot Copy URL");
});
</script>
</script>
</body>
</html>

View File

@ -1,82 +1,75 @@
@extends('layout.default')
@section('title')
Welcome
Welcome
@endsection
@section('subtitle')
The Simple URL Shortener
The Simple URL Shortener
@endsection
@section('content')
<div class="box box-default">
<div class="box-body">
<form action="/" id="shorten-url-form">
<input type="text" class="form-control" placeholder="Enter your URL" id="shorten-url-form-field-url"/>
<br/>
<div class="form-group">
<label>Expired Date</label>
<div class="box box-default">
<div class="box-body">
<form action="/" id="shorten-url-form">
<input type="text" class="form-control" placeholder="Enter your URL" id="shorten-url-form-field-url" />
<br />
<div class="form-group">
<label>Expired Date</label>
<div class="input-group date">
<div class="input-group-addon">
<input type="checkbox" id="shorten-url-form-field-expiration-date-checkbox"/>
</div>
<input type="text"
class="form-control pull-right"
id="shorten-url-form-field-expiration-date"
placeholder="Set expired date" readonly>
<div class="input-group date">
<div class="input-group-addon">
<input type="checkbox" id="shorten-url-form-field-expiration-date-checkbox" />
</div>
<!-- /.input group -->
<input type="text" class="form-control pull-right" id="shorten-url-form-field-expiration-date"
placeholder="Set expired date" readonly>
</div>
<!-- /input-group -->
<div class="form-group">
<label>Password Protection</label>
<!-- /.input group -->
</div>
<!-- /input-group -->
<div class="form-group">
<label>Password Protection</label>
<div class="input-group date">
<div class="input-group-addon">
<input type="checkbox" id="shorten-url-form-field-password-checkbox"/>
</div>
<input type="password"
class="form-control pull-right"
placeholder="Insert password"
id="shorten-url-form-field-password">
<div class="input-group date">
<div class="input-group-addon">
<input type="checkbox" id="shorten-url-form-field-password-checkbox" />
</div>
<!-- /.input group -->
<input type="password" class="form-control pull-right" placeholder="Insert password"
id="shorten-url-form-field-password">
</div>
<br/>
<div class="row">
<div class="col-md-2 col-sm-4">
<button type="submit" class="btn btn-info btn-flat btn-block">
<span>Shorten URL</span>
</button>
</div>
<div class="col-md-10 col-sm-8">
<br class="visible-xs"/>
<div class="input-group" id="shorten-url-form-field-url-generated-group" style="display: none;">
<input type="text"
class="form-control"
placeholder="Generated URL"
id="shorten-url-form-field-url-generated"
readonly>
<span class="input-group-btn">
<button type="button" class="btn btn-danger btn-flat"
data-clipboard-target="#shorten-url-form-field-url-generated">
<i class="fa fa-clipboard"></i>
</button>
</span>
</div>
<!-- /.input group -->
</div>
<br />
<div class="row">
<div class="col-md-2 col-sm-4">
<button type="submit" class="btn btn-info btn-flat btn-block">
<span>Shorten URL</span>
</button>
</div>
<div class="col-md-10 col-sm-8">
<br class="visible-xs" />
<div class="input-group" id="shorten-url-form-field-url-generated-group" style="display: none;">
<input type="text" class="form-control" placeholder="Generated URL"
id="shorten-url-form-field-url-generated" readonly>
<span class="input-group-btn">
<button type="button" class="btn btn-danger btn-flat"
data-clipboard-target="#shorten-url-form-field-url-generated">
<i class="fa fa-clipboard"></i>
</button>
</span>
</div>
</div>
</form>
</div>
<!-- /.box-body -->
</div>
</form>
</div>
<!-- /.box -->
<!-- /.box-body -->
</div>
<!-- /.box -->
@endsection
@section('js')
<script type="application/javascript">
const clipboard = new ClipboardJS('.btn');
<script type="application/javascript">
const clipboard = new ClipboardJS('.btn');
$('#shorten-url-form-field-expiration-date').datepicker({
autoclose: true,
@ -129,5 +122,5 @@
});
});
});
</script>
</script>
@endsection

View File

@ -1,10 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Short URL</title>
<link rel="shortcut icon" href="{{asset('favicon.png')}}"/>
<link rel="shortcut icon" href="{{asset('favicon.png')}}" />
<!-- Tell the browser to be responsive to screen width -->
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<!-- Bootstrap 3.3.7 -->
@ -21,8 +22,7 @@
<link rel="stylesheet" href="{{asset('vendor/toastr/toastr.min.css')}}">
<!-- Theme style -->
<link rel="stylesheet" href="{{asset('dist/css/AdminLTE.min.css')}}">
<!-- AdminLTE Skins. Choose a skin from the css/skins
folder instead of downloading all of them to reduce the load. -->
<!-- AdminLTE Skins. Choose a skin from the css/skins folder instead of downloading all of them to reduce the load. -->
<link rel="stylesheet" href="{{asset('dist/css/skins/_all-skins.min.css')}}">
<style type="text/css">
@ -40,31 +40,30 @@
<!-- Google Font -->
<link rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic">
href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic">
@yield('css')
</head>
<!-- ADD THE CLASS layout-top-nav TO REMOVE THE SIDEBAR. -->
<body class="hold-transition skin-blue layout-top-nav">
<div class="wrapper">
<header class="main-header">
<nav class="navbar navbar-static-top">
<div class="container">
<div class="navbar-header">
<a href="/" class="navbar-brand"><b>Short</b>&nbsp;URL</a>
<button type="button"
class="navbar-toggle collapsed"
data-toggle="collapse"
data-target="#navbar-collapse">
<i class="fa fa-bars"></i>
</button>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse pull-left" id="navbar-collapse">
<ul class="nav navbar-nav">
<li><a href="/">Home</a></li>
@if(Session::get('user') != null)
<body class="hold-transition skin-blue layout-top-nav">
<div class="wrapper">
<header class="main-header">
<nav class="navbar navbar-static-top">
<div class="container">
<div class="navbar-header">
<a href="/" class="navbar-brand"><b>Short</b>&nbsp;URL</a>
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
data-target="#navbar-collapse">
<i class="fa fa-bars"></i>
</button>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse pull-left" id="navbar-collapse">
<ul class="nav navbar-nav">
<li><a href="/">Home</a></li>
@if(Session::get('user') != null)
<li>
<a href="/list">
My URL Shortener
@ -75,12 +74,12 @@
Change Password
</a>
</li>
@endif
</ul>
</div>
<div class="navbar-custom-menu">
<ul class="nav navbar-nav">
@if(Session::get('user') == null)
@endif
</ul>
</div>
<div class="navbar-custom-menu">
<ul class="nav navbar-nav">
@if(Session::get('user') == null)
<li>
<a href="#" data-toggle="modal" data-target="#sign-in-modal">
<span>Sign In</span>
@ -91,56 +90,56 @@
<span>Register</span>
</a>
</li>
@else
@else
<li>
<a href="#" class="logout-button">
<span>Sign Out</span>
</a>
</li>
@endif
</ul>
</div>
</div>
<!-- /.container-fluid -->
</nav>
</header>
<!-- Full Width Column -->
<div class="content-wrapper">
<div class="container">
<!-- Content Header (Page header) -->
<section class="content-header">
<h1>
@yield('title')
<small>@yield('subtitle')</small>
<div class="pull-right">
@yield('top-button')
@endif
</ul>
</div>
</h1>
</section>
</div>
<!-- /.container-fluid -->
</nav>
</header>
<!-- Full Width Column -->
<div class="content-wrapper">
<div class="container">
<!-- Content Header (Page header) -->
<section class="content-header">
<h1>
@yield('title')
<small>@yield('subtitle')</small>
<div class="pull-right">
@yield('top-button')
</div>
</h1>
</section>
<!-- Main content -->
<section class="content">
@yield('content')
</section>
<!-- /.content -->
</div>
<!-- /.container -->
</div>
<!-- /.content-wrapper -->
<footer class="main-footer">
<div class="container">
<div class="pull-right hidden-xs">
<b>Version</b> 1.0.2
<!-- Main content -->
<section class="content">
@yield('content')
</section>
<!-- /.content -->
</div>
Copyright &copy; @php echo date('Y'); @endphp <b>Short</b>&nbsp;URL. All rights reserved.
<!-- /.container -->
</div>
<!-- /.container -->
</footer>
</div>
<!-- ./wrapper -->
<!-- /.content-wrapper -->
@if(Session::get('user') == null)
<footer class="main-footer">
<div class="container">
<div class="pull-right hidden-xs">
<b>Version</b> 1.0.2
</div>
Copyright &copy; @php echo date('Y'); @endphp <b>Short</b>&nbsp;URL. All rights reserved.
</div>
<!-- /.container -->
</footer>
</div>
<!-- ./wrapper -->
@if(Session::get('user') == null)
{{-- Forgot Password Modal --}}
<div class="modal fade" id="forgot-password-modal">
<div class="modal-dialog">
@ -153,7 +152,7 @@
<div class="form-group">
<label>Email</label>
<input type="email" class="form-control" placeholder="Insert your email"
id="forgot-password-modal-form-field-email">
id="forgot-password-modal-form-field-email">
</div>
</div>
<div class="modal-footer">
@ -182,18 +181,18 @@
<div class="form-group">
<label>Email</label>
<input type="email" class="form-control" placeholder="Insert your email"
id="sign-in-modal-form-field-email">
id="sign-in-modal-form-field-email">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" placeholder="Insert your new password"
id="sign-in-modal-form-field-password">
id="sign-in-modal-form-field-password">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default pull-left" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-danger pull-left"
id="sign-in-modal-button-forgot-password">Forgot Password
id="sign-in-modal-button-forgot-password">Forgot Password
</button>
<button type="submit" class="btn btn-primary">
<i class="fa fa-spinner fa-spin" id="sign-in-modal-save-loading-indicator"></i>
@ -219,22 +218,22 @@
<div class="form-group">
<label>Name</label>
<input type="text" class="form-control" placeholder="Insert your name"
id="register-modal-form-field-name">
id="register-modal-form-field-name">
</div>
<div class="form-group">
<label>Email</label>
<input type="email" class="form-control" placeholder="Insert your email"
id="register-modal-form-field-email">
id="register-modal-form-field-email">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" placeholder="Insert your new password"
id="register-modal-form-field-password">
id="register-modal-form-field-password">
</div>
<div class="form-group">
<label>Confirm Password</label>
<input type="password" class="form-control" placeholder="Please confirm new password"
id="register-modal-form-password-confirm">
id="register-modal-form-password-confirm">
</div>
</div>
<div class="modal-footer">
@ -250,7 +249,7 @@
</div>
<!-- /.modal-dialog -->
</div>
@else
@else
{{-- Change Password Modal --}}
<div class="modal fade" id="change-password-modal">
<div class="modal-dialog">
@ -263,12 +262,12 @@
<div class="form-group">
<label>New Password</label>
<input type="password" class="form-control" placeholder="Insert your new password"
id="change-password-modal-form-field-password">
id="change-password-modal-form-field-password">
</div>
<div class="form-group">
<label>Confirm Password</label>
<input type="password" class="form-control" placeholder="Please confirm new password"
id="change-password-modal-form-field-password-confirm">
id="change-password-modal-form-field-password-confirm">
</div>
</div>
<div class="modal-footer">
@ -284,33 +283,33 @@
</div>
<!-- /.modal-dialog -->
</div>
@endif
@endif
<!-- jQuery 3 -->
<script src="{{asset('vendor/jquery/dist/jquery.min.js')}}"></script>
<!-- Bootstrap 3.3.7 -->
<script src="{{asset('vendor/bootstrap/dist/js/bootstrap.min.js')}}"></script>
<!-- SlimScroll -->
<script src="{{asset('vendor/jquery-slimscroll/jquery.slimscroll.min.js')}}"></script>
<!-- FastClick -->
<script src="{{asset('vendor/fastclick/lib/fastclick.js')}}"></script>
<!-- Sweet Alert -->
<script src="{{asset('vendor/sweetalert/sweetalert.min.js')}}"></script>
<!-- Toastr -->
<script src="{{asset('vendor/toastr/toastr.min.js')}}"></script>
<!-- Bootstrap Datepicker -->
<script src="{{asset('vendor/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js')}}"></script>
<!-- iCheck 1.0.1 -->
<script src="{{asset('plugin/iCheck/icheck.min.js')}}"></script>
<!-- Clipboard -->
<script src="{{asset('vendor/clipboard.js/dist/clipboard.min.js')}}"></script>
<!-- AdminLTE App -->
<script src="{{asset('dist/js/adminlte.min.js')}}"></script>
<!-- AdminLTE for demo purposes -->
<script src="{{asset('dist/js/demo.js')}}"></script>
<!-- jQuery 3 -->
<script src="{{asset('vendor/jquery/dist/jquery.min.js')}}"></script>
<!-- Bootstrap 3.3.7 -->
<script src="{{asset('vendor/bootstrap/dist/js/bootstrap.min.js')}}"></script>
<!-- SlimScroll -->
<script src="{{asset('vendor/jquery-slimscroll/jquery.slimscroll.min.js')}}"></script>
<!-- FastClick -->
<script src="{{asset('vendor/fastclick/lib/fastclick.js')}}"></script>
<!-- Sweet Alert -->
<script src="{{asset('vendor/sweetalert/sweetalert.min.js')}}"></script>
<!-- Toastr -->
<script src="{{asset('vendor/toastr/toastr.min.js')}}"></script>
<!-- Bootstrap Datepicker -->
<script src="{{asset('vendor/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js')}}"></script>
<!-- iCheck 1.0.1 -->
<script src="{{asset('plugin/iCheck/icheck.min.js')}}"></script>
<!-- Clipboard -->
<script src="{{asset('vendor/clipboard.js/dist/clipboard.min.js')}}"></script>
<!-- AdminLTE App -->
<script src="{{asset('dist/js/adminlte.min.js')}}"></script>
<!-- AdminLTE for demo purposes -->
<script src="{{asset('dist/js/demo.js')}}"></script>
<script type="application/javascript">
$(document).ready(function () {
<script type="application/javascript">
$(document).ready(function () {
@if(Session::get('user') == null)
$("#forgot-password-modal-save-loading-indicator").hide();
$("#sign-in-modal-save-loading-indicator").hide();
@ -478,9 +477,10 @@
});
@endif
});
</script>
</script>
@yield('js')
@yield('js')
</body>
</html>

View File

@ -1,24 +1,24 @@
@extends('layout.default')
@section('title')
My URL Shortener
My URL Shortener
@endsection
@section('subtitle')
List all of your own URL Shortener
List all of your own URL Shortener
@endsection
@section('content')
<div class="box box-info">
<div class="box-header">
<h3 class="box-title"></h3>
<div class="box box-info">
<div class="box-header">
<h3 class="box-title"></h3>
<div class="box-tools"></div>
</div>
<!-- /.box-header -->
<div class="box-body" style="overflow-x: auto;">
<table class="table table-bordered">
<thead>
<div class="box-tools"></div>
</div>
<!-- /.box-header -->
<div class="box-body" style="overflow-x: auto;">
<table class="table table-bordered">
<thead>
<tr>
<th style="width:10px;text-align: center;">No</th>
<th>Destination</th>
@ -28,30 +28,30 @@
<th>Protection</th>
<th>Action</th>
</tr>
</thead>
<tbody id="table-url-address-body">
</thead>
<tbody id="table-url-address-body">
<tr>
<td colspan="6" style="text-align:center;color:#777;">
<i class="fa fa-spinner fa-spin"></i>
</td>
</tr>
</tbody>
</table>
</div>
<!-- /.box-body -->
<div class="box-footer">
Page <span id="current-page">1</span>,
Showing <span id="range-start-data">0</span> to <span id="range-end-data">0</span>
of <span id="total-entries">0</span> entries
<ul class="pagination pagination-sm no-margin pull-right" id="pagination-button"></ul>
</div>
</tbody>
</table>
</div>
<!-- /.box -->
<!-- /.box-body -->
<div class="box-footer">
Page <span id="current-page">1</span>,
Showing <span id="range-start-data">0</span> to <span id="range-end-data">0</span>
of <span id="total-entries">0</span> entries
<ul class="pagination pagination-sm no-margin pull-right" id="pagination-button"></ul>
</div>
</div>
<!-- /.box -->
@endsection
@section('js')
<script type="application/javascript">
const clipboard = new ClipboardJS('.btn');
<script type="application/javascript">
const clipboard = new ClipboardJS('.btn');
let page = 1;
let canPageNext = false;
@ -186,5 +186,5 @@
// Initialize
loadURLAddress();
});
</script>
</script>
@endsection

View File

@ -1,11 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="csrf_token" content="{{ csrf_token() }}"/>
<meta name="csrf_token" content="{{ csrf_token() }}" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Short URL</title>
<link rel="shortcut icon" href="{{asset('favicon.png')}}"/>
<link rel="shortcut icon" href="{{asset('favicon.png')}}" />
<!-- Tell the browser to be responsive to screen width -->
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<!-- Bootstrap 3.3.7 -->
@ -30,48 +31,49 @@
<!-- Google Font -->
<link rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic">
href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic">
</head>
<body class="hold-transition login-page">
<div class="login-box">
<div class="login-logo">
<a href="/"><b>Short</b>&nbsp;URL</a>
</div>
<!-- /.login-logo -->
<div class="login-box-body">
<p class="login-box-msg">Protected URL</p>
<div class="login-box">
<div class="login-logo">
<a href="/"><b>Short</b>&nbsp;URL</a>
</div>
<!-- /.login-logo -->
<div class="login-box-body">
<p class="login-box-msg">Protected URL</p>
<form action="/" method="post" id="protection-form">
<div class="form-group has-feedback">
<input type="password" class="form-control" placeholder="Password" id="password">
<span class="glyphicon glyphicon-lock form-control-feedback"></span>
</div>
<div class="row">
<div class="col-xs-8"></div>
<!-- /.col -->
<div class="col-xs-4">
<button type="submit" class="btn btn-primary btn-block btn-flat">
Open Link
</button>
<form action="/" method="post" id="protection-form">
<div class="form-group has-feedback">
<input type="password" class="form-control" placeholder="Password" id="password">
<span class="glyphicon glyphicon-lock form-control-feedback"></span>
</div>
<!-- /.col -->
</div>
</form>
<div class="row">
<div class="col-xs-8"></div>
<!-- /.col -->
<div class="col-xs-4">
<button type="submit" class="btn btn-primary btn-block btn-flat">
Open Link
</button>
</div>
<!-- /.col -->
</div>
</form>
</div>
<!-- /.login-box-body -->
</div>
<!-- /.login-box-body -->
</div>
<!-- /.login-box -->
<!-- /.login-box -->
<!-- jQuery 3 -->
<script src="{{asset('vendor/jquery/dist/jquery.min.js')}}"></script>
<!-- Bootstrap 3.3.7 -->
<script src="{{asset('vendor/bootstrap/dist/js/bootstrap.min.js')}}"></script>
<!-- Toastr -->
<script src="{{asset('vendor/toastr/toastr.min.js')}}"></script>
<!-- iCheck -->
<script src="{{asset('plugin/iCheck/icheck.min.js')}}"></script>
<script>
$(document).ready(function () {
<!-- jQuery 3 -->
<script src="{{asset('vendor/jquery/dist/jquery.min.js')}}"></script>
<!-- Bootstrap 3.3.7 -->
<script src="{{asset('vendor/bootstrap/dist/js/bootstrap.min.js')}}"></script>
<!-- Toastr -->
<script src="{{asset('vendor/toastr/toastr.min.js')}}"></script>
<!-- iCheck -->
<script src="{{asset('plugin/iCheck/icheck.min.js')}}"></script>
<script>
$(document).ready(function () {
$("#protection-form").on("submit", function (e) {
e.preventDefault();
$.ajax({
@ -96,6 +98,7 @@
});
});
});
</script>
</script>
</body>
</html>

View File

@ -1,5 +1,5 @@
<div>
Hi, {{ $name }}<br/>
This is your new password : {{ $password }}<br/>
Hi, {{ $name }}<br />
This is your new password : {{ $password }}<br />
<p>You can change it after login back</p>
</div>