Got basic redirect working
This commit is contained in:
parent
f59bab2b4a
commit
d03bab8e02
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Models\Shortlink;
|
||||||
|
|
||||||
|
class ShortlinkController extends Controller
|
||||||
|
{
|
||||||
|
public function create(Request $request) {
|
||||||
|
if (auth()->user() == null) {
|
||||||
|
return response()->json(['error' => 'Unauthorized'], 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$request->validate([
|
||||||
|
'url' => 'required|url'
|
||||||
|
]);
|
||||||
|
|
||||||
|
//check if url returns 200 at its final redirect
|
||||||
|
|
||||||
|
$shortlink = new Shortlink();
|
||||||
|
$shortlink->create($request->url, auth()->id());
|
||||||
|
return redirect("/l/{$shortlink->shortid}");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return back()->withErrors([
|
||||||
|
'error' => $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function goto(Request $request, $id) {
|
||||||
|
try {
|
||||||
|
$shortlink = (new Shortlink())->get($id);
|
||||||
|
// check if the link is expired or if it has reached the max clicks
|
||||||
|
// log the interaction
|
||||||
|
return redirect($shortlink->destination);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return response()->json(['error' => $e->getMessage()], 404);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Shortlink extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'shortid',
|
||||||
|
'destination',
|
||||||
|
'user_id',
|
||||||
|
'max_clicks',
|
||||||
|
'expires_at',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function create(string $url, int $user_id): Shortlink {
|
||||||
|
$this->shortid = $this->generateNewId();
|
||||||
|
$this->destination = $url;
|
||||||
|
$this->user_id = $user_id;
|
||||||
|
$this->max_clicks = 0;
|
||||||
|
$this->expires_at = null;
|
||||||
|
$this->save();
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(string $id): Shortlink {
|
||||||
|
$shortlink = Shortlink::where('shortid', $id)->first();
|
||||||
|
if ($shortlink == null) {
|
||||||
|
throw new \Exception('This shortened link does not exist');
|
||||||
|
}
|
||||||
|
return $shortlink;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(): void {
|
||||||
|
Shortlink::where('shortid', $this->id)->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function modify(int $max_clicks, $expires_at): void {
|
||||||
|
$this->max_clicks = $max_clicks;
|
||||||
|
$this->expires_at = $expires_at;
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateNewId(int $length = 6): string {
|
||||||
|
$characters = 'qwrtypsdfghjklzxcvbnmQWRTYPSDFGHJKLZXCVBNM256789_';
|
||||||
|
// try n x 2 times to generate a new id, if it finds an id, return it, otherwise, try to look for an id of length + 1
|
||||||
|
for ($i = 0; $i < $length * 2; $i++) {
|
||||||
|
$id = '';
|
||||||
|
for ($i = 0; $i < $length; $i++) {
|
||||||
|
$id .= $characters[rand(0, strlen($characters) - 1)];
|
||||||
|
}
|
||||||
|
if (Shortlink::where('shortid', $id)->count() == 0) {
|
||||||
|
return $id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this->generateNewId($length + 1);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('shortlinks', function (Blueprint $table) {
|
||||||
|
$table->string('shortid')->unique()->primary();
|
||||||
|
$table->string('destination');
|
||||||
|
$table->foreignId('user_id')->references('id')->on('users');
|
||||||
|
$table->integer('max_clicks')->default(0);
|
||||||
|
$table->timestamp('expires_at')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::create('link_interactions', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('link');
|
||||||
|
$table->foreign('link')->references('shortid')->on('shortlinks');
|
||||||
|
$table->string('ip');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('shortlinks');
|
||||||
|
Schema::dropIfExists('link_interactions');
|
||||||
|
}
|
||||||
|
};
|
|
@ -121,3 +121,44 @@ header nav a {
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#shortener-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 60px 50px;
|
||||||
|
background-color: var(--primary);
|
||||||
|
width: calc(100% - 100px);
|
||||||
|
gap: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#shortener-container h1 {
|
||||||
|
font-size: 2.5em;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#shortener-container input {
|
||||||
|
color: black;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 1.3em;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding: 10px;
|
||||||
|
border: 0;
|
||||||
|
width: 600px;
|
||||||
|
box-shadow: 2px 2px 5px 0 #0004;
|
||||||
|
}
|
||||||
|
|
||||||
|
#shortener-container button {
|
||||||
|
font-size: 1.3em;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
color: white;
|
||||||
|
box-shadow: 2px 2px 5px 0 #0004;
|
||||||
|
background-color: var(--foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
#shortener-container input::placeholder {
|
||||||
|
color: #aaa;
|
||||||
|
}
|
|
@ -5,6 +5,21 @@
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<h1>HOMEPAGE!</h1>
|
<div id="shortener-container">
|
||||||
<p>Placeholder text</p>
|
@if (auth()->check())
|
||||||
|
<h1>Shorten your URL</h1>
|
||||||
|
<form action="shorten" method="post">
|
||||||
|
@csrf
|
||||||
|
<input type="text" name="url" placeholder="Enter your URL here" required>
|
||||||
|
<button type="submit">Shorten</button>
|
||||||
|
</form>
|
||||||
|
@if ($errors->any())
|
||||||
|
<p class="error">{{ $errors->first() }}</p>
|
||||||
|
@endif
|
||||||
|
@else
|
||||||
|
<h1>Welcome to slink URL Shortener</h1>
|
||||||
|
<p><a href="register">Sign Up</a> or <a href="login">Log In</a> to shorten your URLs</p>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
@endsection
|
@endsection
|
|
@ -3,6 +3,7 @@
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
use App\Http\Controllers\RegisterController;
|
use App\Http\Controllers\RegisterController;
|
||||||
use App\Http\Controllers\LoginController;
|
use App\Http\Controllers\LoginController;
|
||||||
|
use App\Http\Controllers\ShortlinkController;
|
||||||
|
|
||||||
Route::get('/', function () {
|
Route::get('/', function () {
|
||||||
return view('welcome');
|
return view('welcome');
|
||||||
|
@ -44,3 +45,9 @@ Route::get('/home', function () {
|
||||||
}
|
}
|
||||||
return view('home');
|
return view('home');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Route::post('/shorten', [ShortlinkController::class, 'create']);
|
||||||
|
|
||||||
|
// Route::get('/l/{id}', );
|
||||||
|
|
||||||
|
Route::get('/{id}', [ShortlinkController::class, 'goto']);
|
Loading…
Reference in New Issue