diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 41d5dee..0000000 --- a/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ - -.env - -*.pyc diff --git a/README.md b/README.md index 45afb30..f185514 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,44 @@ -# shortlink +# Shorten! -NOTE: Don't make in public. KEYS EXPOSED +The Shorten Web Application allows users to generate shortened URLs for their long URLs. It is a simple and easy-to-use tool built using HTML, CSS, and JavaScript. + +## Features + +- Generates short URLs for long URLs to make them more manageable and shareable. +- Uses the short.io API service to handle URL shortening and redirection. +- Provides a clean and intuitive user interface for quick URL shortening. + +## Prerequisites + +Before getting started, make sure you have the following: + +- A domain or subdomain to host the application. +- Registration of your domain/subdomain with short.io to obtain a public API key. + +## Installation and Setup + +1. Fork this repository to your GitHub account. +2. Clone the forked repository to your local machine. +3. Register your domain/subdomain with short.io to generate a public API key. +4. Open the `assets/script.js` file in a text editor. +5. Replace the placeholder API key in the `'authorization'` field with your short.io API key. +6. Rename the domain `'link.laavesh.ml'` to your own domain or subdomain in the following files: + - `index.html` + - `assets/script.js` + +## Usage + +1. Deploy the application to your domain or subdomain. +2. Visit your domain or subdomain in a web browser. +3. Enter a long URL in the input field. +4. Click on the "Shorten" button. +5. The application will generate a shortened URL using the short.io API and display it to the user. +6. Copy the shortened URL and use it wherever you need. + +## Contributing + +Contributions are welcome! If you have any suggestions, improvements, or bug fixes, feel free to create a pull request. + +## License + +This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. diff --git a/assets/script.js b/assets/script.js index 165f3fd..0436576 100644 --- a/assets/script.js +++ b/assets/script.js @@ -21,6 +21,7 @@ document.getElementById("myinput").onclick = function () { // data to be sent to the API var data = { + // domain -- change here if you want to use your own domain domain: "link.laavesh.ml", originalURL: link, allowDuplicates: false, @@ -37,6 +38,7 @@ document.getElementById("myinput").onclick = function () { headers: { accept: "application/json", "Content-Type": "application/json", + // API key -- change here if you want to use your own API key (public key) authorization: "pk_ynFkEXQHXdWrijOF", }, body: JSON.stringify(data), diff --git a/edit.py b/edit.py deleted file mode 100644 index 33aaa86..0000000 --- a/edit.py +++ /dev/null @@ -1,23 +0,0 @@ -import requests -from dotenv import load_dotenv -import os -load_dotenv() - -url = "https://api.short.io/links/lnk_2MDV_9dCPkoujKaJ" - -import json - -# https://developers.short.io/docs/updating-an-existing-short-url - -payload = json.dumps({"allowDuplicates": False, "domain": "link.laavesh.ml", "originalURL": "google.com" }) -headers = { - 'accept': "application/json", - 'content-type': "application/json", - 'authorization': os.getenv("API_KEY") -} - -response = requests.request("POST", url, data=payload, headers=headers) - -res = json.dumps(response.json(), indent=4) - -print(res) \ No newline at end of file diff --git a/short/db.sqlite3 b/short/db.sqlite3 deleted file mode 100644 index e69de29..0000000 diff --git a/short/manage.py b/short/manage.py deleted file mode 100644 index 27b3c5d..0000000 --- a/short/manage.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python -"""Django's command-line utility for administrative tasks.""" -import os -import sys - - -def main(): - """Run administrative tasks.""" - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'short.settings') - try: - from django.core.management import execute_from_command_line - except ImportError as exc: - raise ImportError( - "Couldn't import Django. Are you sure it's installed and " - "available on your PYTHONPATH environment variable? Did you " - "forget to activate a virtual environment?" - ) from exc - execute_from_command_line(sys.argv) - - -if __name__ == '__main__': - main() diff --git a/short/short/__init__.py b/short/short/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/short/short/asgi.py b/short/short/asgi.py deleted file mode 100644 index c3e84dd..0000000 --- a/short/short/asgi.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -ASGI config for short project. - -It exposes the ASGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/4.1/howto/deployment/asgi/ -""" - -import os - -from django.core.asgi import get_asgi_application - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'short.settings') - -application = get_asgi_application() diff --git a/short/short/settings.py b/short/short/settings.py deleted file mode 100644 index 5e2e5b6..0000000 --- a/short/short/settings.py +++ /dev/null @@ -1,124 +0,0 @@ -""" -Django settings for short project. - -Generated by 'django-admin startproject' using Django 4.1.7. - -For more information on this file, see -https://docs.djangoproject.com/en/4.1/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/4.1/ref/settings/ -""" - -from pathlib import Path - -# Build paths inside the project like this: BASE_DIR / 'subdir'. -BASE_DIR = Path(__file__).resolve().parent.parent - - -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/ - -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'django-insecure-e&n6=9kn%@tk+#cn%!f1^fvpixkn(g14i362(63sf&y8p!#n!0' - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True - -ALLOWED_HOSTS = [] - - -# Application definition - -INSTALLED_APPS = [ - 'transfer', - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', -] - -MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', -] - -ROOT_URLCONF = 'short.urls' - -TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - ], - }, - }, -] - -WSGI_APPLICATION = 'short.wsgi.application' - - -# Database -# https://docs.djangoproject.com/en/4.1/ref/settings/#databases - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': BASE_DIR / 'db.sqlite3', - } -} - - -# Password validation -# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators - -AUTH_PASSWORD_VALIDATORS = [ - { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', - }, -] - - -# Internationalization -# https://docs.djangoproject.com/en/4.1/topics/i18n/ - -LANGUAGE_CODE = 'en-us' - -TIME_ZONE = 'UTC' - -USE_I18N = True - -USE_TZ = True - - -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/4.1/howto/static-files/ - -STATIC_URL = 'static/' - -# Default primary key field type -# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field - -DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' diff --git a/short/short/urls.py b/short/short/urls.py deleted file mode 100644 index fc72fef..0000000 --- a/short/short/urls.py +++ /dev/null @@ -1,22 +0,0 @@ -"""short URL Configuration - -The `urlpatterns` list routes URLs to views. For more information please see: - https://docs.djangoproject.com/en/4.1/topics/http/urls/ -Examples: -Function views - 1. Add an import: from my_app import views - 2. Add a URL to urlpatterns: path('', views.home, name='home') -Class-based views - 1. Add an import: from other_app.views import Home - 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') -Including another URLconf - 1. Import the include() function: from django.urls import include, path - 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) -""" -from django.contrib import admin -from django.urls import path, include - -urlpatterns = [ - path('admin/', admin.site.urls), - path('transfer', include('transfer.urls')), -] diff --git a/short/short/wsgi.py b/short/short/wsgi.py deleted file mode 100644 index 7de5d5e..0000000 --- a/short/short/wsgi.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -WSGI config for short project. - -It exposes the WSGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/4.1/howto/deployment/wsgi/ -""" - -import os - -from django.core.wsgi import get_wsgi_application - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'short.settings') - -application = get_wsgi_application() diff --git a/short/transfer/__init__.py b/short/transfer/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/short/transfer/admin.py b/short/transfer/admin.py deleted file mode 100644 index 8c38f3f..0000000 --- a/short/transfer/admin.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/short/transfer/apps.py b/short/transfer/apps.py deleted file mode 100644 index 64322ff..0000000 --- a/short/transfer/apps.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.apps import AppConfig - - -class TransferConfig(AppConfig): - default_auto_field = 'django.db.models.BigAutoField' - name = 'transfer' diff --git a/short/transfer/migrations/__init__.py b/short/transfer/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/short/transfer/models.py b/short/transfer/models.py deleted file mode 100644 index 71a8362..0000000 --- a/short/transfer/models.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.db import models - -# Create your models here. diff --git a/short/transfer/static/transfer/copy.png b/short/transfer/static/transfer/copy.png deleted file mode 100644 index b0c3aa8..0000000 Binary files a/short/transfer/static/transfer/copy.png and /dev/null differ diff --git a/short/transfer/static/transfer/favicon.png b/short/transfer/static/transfer/favicon.png deleted file mode 100644 index 4517ee7..0000000 Binary files a/short/transfer/static/transfer/favicon.png and /dev/null differ diff --git a/short/transfer/static/transfer/script.js b/short/transfer/static/transfer/script.js deleted file mode 100644 index bf6c15f..0000000 --- a/short/transfer/static/transfer/script.js +++ /dev/null @@ -1,79 +0,0 @@ - - -document.addEventListener("DOMContentLoaded", function () { - - // get the submit button - document.getElementById("myinput").onclick = function () { - // get the link from the input - var link = document.getElementById("linkinput").value; - var csrf = document.getElementsByName("csrfmiddlewaretoken")[0].value; - var message = document.getElementById("message"); - - - console.log(csrf) - // data to be sent to the transfer view - console.log(link) - - fetch("/transfer", { - method: "post", - headers: { - accept: "application/json", - "Content-Type": "application/json", - "X-CSRFToken": csrf, - }, - body: JSON.stringify({ - link: link, - }), - }) - .then(function (response) { - return response.json(); - }) - .then(function (data) { - if (data.error) { - throw data.error; - } - // show link updated - // Get the text field - - let url = "we.laavesh.ml"; - message.innerHTML = "Updated!"; - console.log("Updated!"); - - // Change back to link after 800ms - setTimeout(function () { - message.innerHTML = url; - }, 800); - }) - - - document.getElementById("linkinput").value = ""; - } - -}); - - - -// Copy the link to the clipboard -document.getElementById("copy").onclick = function () { - // Get the text field - var message = document.getElementById("message"); - - // get the link - url = message.innerHTML; - - - // Copy link to clipboard - navigator.clipboard.writeText(url); - - // Alert copied to clipboard - message.innerHTML = "Copied!"; - console.log("Copied!"); - - // Change back to link after 800ms - setTimeout(function () { - message.innerHTML = url; - }, 800); - - - -} \ No newline at end of file diff --git a/short/transfer/static/transfer/styles.css b/short/transfer/static/transfer/styles.css deleted file mode 100644 index 89571d6..0000000 --- a/short/transfer/static/transfer/styles.css +++ /dev/null @@ -1,242 +0,0 @@ -@import url("https://fonts.googleapis.com/css2?family=Josefin+Sans&display=swap"); - -html { - height: 100%; -} -body { - margin: 0; - padding: 0; - font-family: "Josefin Sans", sans-serif; - background: linear-gradient(#141e30, #243b55); -} - -.login-box { - position: absolute; - top: 50%; - left: 50%; - width: 620px; - padding: 40px; - transform: translate(-50%, -50%); - background: rgba(0, 0, 0, 0.5); - box-sizing: border-box; - box-shadow: 0 15px 25px rgba(0, 0, 0, 0.6); - border-radius: 10px; -} - -.login-box h2 { - margin: 0 0 30px; - padding: 0; - color: #fff; - text-align: center; -} - -.login-box .user-box { - position: relative; -} - -.login-box .user-box input { - width: 100%; - padding: 10px 0; - font-size: 20px; - color: #fff; - margin-bottom: 30px; - border: none; - border-bottom: 1px solid #fff; - outline: none; - background: transparent; -} -.login-box .user-box label { - position: absolute; - top: 0; - left: 0; - padding: 10px 0; - font-size: 20px; - color: #fff; - pointer-events: none; - transition: 0.5s; -} - -.login-box .user-box input:focus ~ label, -.login-box .user-box input:valid ~ label { - top: -20px; - left: 0; - color: #03e9f4; - font-size: 16px; -} - -.login-box form a { - position: relative; - display: inline-block; - padding: 18px 20px 15px 20px; - color: #03e9f4; - font-size: 14px; - text-decoration: none; - text-transform: uppercase; - overflow: hidden; - transition: 0.5s; - margin-top: 16px; - letter-spacing: 4px; -} - -.login-box a:hover { - background: #03e9f4; - color: #fff; - border-radius: 5px; - box-shadow: 0 0 5px #03e9f4, 0 0 25px #03e9f4, 0 0 50px #03e9f4, 0 0 100px #03e9f4; -} - -.login-box a span { - position: absolute; - display: block; -} - -.login-box a span:nth-child(1) { - top: 0; - left: -100%; - width: 100%; - height: 2px; - background: linear-gradient(90deg, transparent, #03e9f4); - animation: btn-anim1 1s linear infinite; -} - -@keyframes btn-anim1 { - 0% { - left: -100%; - } - 50%, - 100% { - left: 100%; - } -} - -.login-box a span:nth-child(2) { - top: -100%; - right: 0; - width: 2px; - height: 100%; - background: linear-gradient(180deg, transparent, #03e9f4); - animation: btn-anim2 1s linear infinite; - animation-delay: 0.25s; -} - -@keyframes btn-anim2 { - 0% { - top: -100%; - } - 50%, - 100% { - top: 100%; - } -} - -.login-box a span:nth-child(3) { - bottom: 0; - right: -100%; - width: 100%; - height: 2px; - background: linear-gradient(270deg, transparent, #03e9f4); - animation: btn-anim3 1s linear infinite; - animation-delay: 0.5s; -} - -@keyframes btn-anim3 { - 0% { - right: -100%; - } - 50%, - 100% { - right: 100%; - } -} - -.login-box a span:nth-child(4) { - bottom: -100%; - left: 0; - width: 2px; - height: 100%; - background: linear-gradient(360deg, transparent, #03e9f4); - animation: btn-anim4 1s linear infinite; - animation-delay: 0.75s; -} - -@keyframes btn-anim4 { - 0% { - bottom: -100%; - } - 50%, - 100% { - bottom: 100%; - } -} - -/* link url display */ -.msg { - display: block; - background: #047b82; - color: #ffffff; - position: relative; - padding: 5px 20px; -} -#message { - padding-top: 4px; -} - -/* two columns for link and clipboard icon */ -.row { - display: flex; -} -.column { - float: left; -} - -.left { - width: 90%; -} - -.right { - width: 10%; -} - -/* clipboard icon */ -.column img { - padding: 10px; -} -.column button { - border: none; - cursor: pointer; - appearance: none; - background-color: inherit; -} - - -/* Media Queries */ - -@media screen and (max-width: 600px) { - body{ - background: linear-gradient(#0c121d, #14212f); - } - - .login-box { - width: 100%; - } - .column img{ - width: 26px; - } -} - -@media screen and (max-width: 500px) { - - .login-box h2 { - font-size: 20px; - } - .login-box .user-box input { - font-size: 16px; - } - .login-box .user-box label { - font-size: 16px; - } - .login-box form a { - font-size: 12px; - } -} - diff --git a/short/transfer/templates/transfer/transfer.html b/short/transfer/templates/transfer/transfer.html deleted file mode 100644 index 5c8c322..0000000 --- a/short/transfer/templates/transfer/transfer.html +++ /dev/null @@ -1,53 +0,0 @@ -{% load static %} - - - -
- - - -we.laavesh.ml
-