Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
5e5e1697bb
|
|||
|
c90e7cfa21
|
|||
|
d67d9fe5a0
|
|||
| 3a6d9cf167 | |||
|
af4de876a5
|
|||
|
60e0545fc4
|
@@ -0,0 +1,3 @@
|
||||
[submodule "Backend/Skycrate"]
|
||||
path = Backend/Skycrate
|
||||
url = https://git.kska.io/notkshitij/SkycrateBackend.git
|
||||
@@ -1,28 +0,0 @@
|
||||
# Info
|
||||
|
||||
---
|
||||
|
||||
## Work distribution
|
||||
|
||||
- Design: Kapil
|
||||
- Frontend: Shivani, Shriniwas, Ombase, Tejas, Sonali, Dinesh
|
||||
- Backend: Vedang, Lalit
|
||||
- DBMS: Lalit
|
||||
- HDFS: Sonali, Prajakta, Poonam
|
||||
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
In this mini project, we'll be creating something similar to Google Drive. There shall be 3 pages, landing, login/registration and main page where all the files uploaded by the user will be shown. Kapil is supposed to design the UI and send it over by Sunday. Based on this design, people in the frontend department shall work on the pages.
|
||||
|
||||
Landing page is basically a home page containing small description of the project, features etc. Login/registration page will ask for username/password. Lalit is expected to implement it using MySQL/MongoDB, i.e. he is responsible for user authentication. Once the user is authenticated, they shall be redirected to the main page where they can view their files, and upload/delete them.
|
||||
|
||||
Vedang is responsible to developing the backend code in Java for encrypting the uploaded files and decrypting the downloaded files. These files will be stored in Hadoop File System (HDFS) which shall be handled by Sonali, Prajakta and Poonam.
|
||||
|
||||
We are planning to make this a good enough project so that we can maybe open source it and make it a part of our resume. Therefore it is important that y'all work sahi se and finish your stuff by the deadlines. We are expected to finish the entire project ✨ before IN-SEM exam ✨
|
||||
|
||||
While you are working on the project, note down the things you are doing so that we can provide it to the people doing the documentation.
|
||||
|
||||
---
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
/mvnw text eol=lf
|
||||
*.cmd text eol=crlf
|
||||
@@ -0,0 +1,33 @@
|
||||
HELP.md
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
@@ -0,0 +1,19 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
wrapperVersion=3.3.2
|
||||
distributionType=only-script
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
|
||||
@@ -0,0 +1,55 @@
|
||||
# API Testing Instructions (Postman)
|
||||
|
||||
## Signup
|
||||
|
||||
**Endpoint:**
|
||||
```
|
||||
POST http://localhost:8081/api/signup
|
||||
```
|
||||
|
||||
**Request Body (JSON):**
|
||||
```json
|
||||
{
|
||||
"firstname": "L",
|
||||
"lastname": "H10",
|
||||
"email": "exmaple@gmail.com",
|
||||
"password": "your_password_here"
|
||||
}
|
||||
```
|
||||
|
||||
**Expected Response:**
|
||||
```json
|
||||
{
|
||||
"id": 2,
|
||||
"username": "exmaple@gmail.com",
|
||||
"password": "hashed_password_here",
|
||||
"createdAt": "your_creation_date_here",
|
||||
"enabled": true,
|
||||
"authorities": [],
|
||||
"credentialsNonExpired": true,
|
||||
"accountNonExpired": true,
|
||||
"accountNonLocked": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Login
|
||||
|
||||
**Endpoint:**
|
||||
```
|
||||
POST http://localhost:8081/api/login
|
||||
```
|
||||
|
||||
**Expected Response:**
|
||||
```json
|
||||
{
|
||||
"token": "your_token_here",
|
||||
"expiresIn": 3600000
|
||||
}
|
||||
```
|
||||
|
||||
### Notes:
|
||||
- Ensure the server is running before making requests.
|
||||
- Use Postman to send POST requests with the specified JSON body.
|
||||
- The token received in the login response can be used for authenticated requests.
|
||||
@@ -0,0 +1,259 @@
|
||||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------------
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Apache Maven Wrapper startup batch script, version 3.3.2
|
||||
#
|
||||
# Optional ENV vars
|
||||
# -----------------
|
||||
# JAVA_HOME - location of a JDK home dir, required when download maven via java source
|
||||
# MVNW_REPOURL - repo url base for downloading maven distribution
|
||||
# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
|
||||
# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
set -euf
|
||||
[ "${MVNW_VERBOSE-}" != debug ] || set -x
|
||||
|
||||
# OS specific support.
|
||||
native_path() { printf %s\\n "$1"; }
|
||||
case "$(uname)" in
|
||||
CYGWIN* | MINGW*)
|
||||
[ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")"
|
||||
native_path() { cygpath --path --windows "$1"; }
|
||||
;;
|
||||
esac
|
||||
|
||||
# set JAVACMD and JAVACCMD
|
||||
set_java_home() {
|
||||
# For Cygwin and MinGW, ensure paths are in Unix format before anything is touched
|
||||
if [ -n "${JAVA_HOME-}" ]; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ]; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
JAVACCMD="$JAVA_HOME/jre/sh/javac"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
JAVACCMD="$JAVA_HOME/bin/javac"
|
||||
|
||||
if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then
|
||||
echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2
|
||||
echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
JAVACMD="$(
|
||||
'set' +e
|
||||
'unset' -f command 2>/dev/null
|
||||
'command' -v java
|
||||
)" || :
|
||||
JAVACCMD="$(
|
||||
'set' +e
|
||||
'unset' -f command 2>/dev/null
|
||||
'command' -v javac
|
||||
)" || :
|
||||
|
||||
if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then
|
||||
echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# hash string like Java String::hashCode
|
||||
hash_string() {
|
||||
str="${1:-}" h=0
|
||||
while [ -n "$str" ]; do
|
||||
char="${str%"${str#?}"}"
|
||||
h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296))
|
||||
str="${str#?}"
|
||||
done
|
||||
printf %x\\n $h
|
||||
}
|
||||
|
||||
verbose() { :; }
|
||||
[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; }
|
||||
|
||||
die() {
|
||||
printf %s\\n "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
trim() {
|
||||
# MWRAPPER-139:
|
||||
# Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.
|
||||
# Needed for removing poorly interpreted newline sequences when running in more
|
||||
# exotic environments such as mingw bash on Windows.
|
||||
printf "%s" "${1}" | tr -d '[:space:]'
|
||||
}
|
||||
|
||||
# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties
|
||||
while IFS="=" read -r key value; do
|
||||
case "${key-}" in
|
||||
distributionUrl) distributionUrl=$(trim "${value-}") ;;
|
||||
distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;;
|
||||
esac
|
||||
done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties"
|
||||
[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties"
|
||||
|
||||
case "${distributionUrl##*/}" in
|
||||
maven-mvnd-*bin.*)
|
||||
MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/
|
||||
case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in
|
||||
*AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;
|
||||
:Darwin*x86_64) distributionPlatform=darwin-amd64 ;;
|
||||
:Darwin*arm64) distributionPlatform=darwin-aarch64 ;;
|
||||
:Linux*x86_64*) distributionPlatform=linux-amd64 ;;
|
||||
*)
|
||||
echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2
|
||||
distributionPlatform=linux-amd64
|
||||
;;
|
||||
esac
|
||||
distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip"
|
||||
;;
|
||||
maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;
|
||||
*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
|
||||
esac
|
||||
|
||||
# apply MVNW_REPOURL and calculate MAVEN_HOME
|
||||
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
|
||||
[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}"
|
||||
distributionUrlName="${distributionUrl##*/}"
|
||||
distributionUrlNameMain="${distributionUrlName%.*}"
|
||||
distributionUrlNameMain="${distributionUrlNameMain%-bin}"
|
||||
MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}"
|
||||
MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")"
|
||||
|
||||
exec_maven() {
|
||||
unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :
|
||||
exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD"
|
||||
}
|
||||
|
||||
if [ -d "$MAVEN_HOME" ]; then
|
||||
verbose "found existing MAVEN_HOME at $MAVEN_HOME"
|
||||
exec_maven "$@"
|
||||
fi
|
||||
|
||||
case "${distributionUrl-}" in
|
||||
*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;
|
||||
*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;;
|
||||
esac
|
||||
|
||||
# prepare tmp dir
|
||||
if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then
|
||||
clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; }
|
||||
trap clean HUP INT TERM EXIT
|
||||
else
|
||||
die "cannot create temp dir"
|
||||
fi
|
||||
|
||||
mkdir -p -- "${MAVEN_HOME%/*}"
|
||||
|
||||
# Download and Install Apache Maven
|
||||
verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
|
||||
verbose "Downloading from: $distributionUrl"
|
||||
verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||
|
||||
# select .zip or .tar.gz
|
||||
if ! command -v unzip >/dev/null; then
|
||||
distributionUrl="${distributionUrl%.zip}.tar.gz"
|
||||
distributionUrlName="${distributionUrl##*/}"
|
||||
fi
|
||||
|
||||
# verbose opt
|
||||
__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''
|
||||
[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v
|
||||
|
||||
# normalize http auth
|
||||
case "${MVNW_PASSWORD:+has-password}" in
|
||||
'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;
|
||||
has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;
|
||||
esac
|
||||
|
||||
if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then
|
||||
verbose "Found wget ... using wget"
|
||||
wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl"
|
||||
elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then
|
||||
verbose "Found curl ... using curl"
|
||||
curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl"
|
||||
elif set_java_home; then
|
||||
verbose "Falling back to use Java to download"
|
||||
javaSource="$TMP_DOWNLOAD_DIR/Downloader.java"
|
||||
targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||
cat >"$javaSource" <<-END
|
||||
public class Downloader extends java.net.Authenticator
|
||||
{
|
||||
protected java.net.PasswordAuthentication getPasswordAuthentication()
|
||||
{
|
||||
return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() );
|
||||
}
|
||||
public static void main( String[] args ) throws Exception
|
||||
{
|
||||
setDefault( new Downloader() );
|
||||
java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
|
||||
}
|
||||
}
|
||||
END
|
||||
# For Cygwin/MinGW, switch paths to Windows format before running javac and java
|
||||
verbose " - Compiling Downloader.java ..."
|
||||
"$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java"
|
||||
verbose " - Running Downloader.java ..."
|
||||
"$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")"
|
||||
fi
|
||||
|
||||
# If specified, validate the SHA-256 sum of the Maven distribution zip file
|
||||
if [ -n "${distributionSha256Sum-}" ]; then
|
||||
distributionSha256Result=false
|
||||
if [ "$MVN_CMD" = mvnd.sh ]; then
|
||||
echo "Checksum validation is not supported for maven-mvnd." >&2
|
||||
echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
|
||||
exit 1
|
||||
elif command -v sha256sum >/dev/null; then
|
||||
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then
|
||||
distributionSha256Result=true
|
||||
fi
|
||||
elif command -v shasum >/dev/null; then
|
||||
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then
|
||||
distributionSha256Result=true
|
||||
fi
|
||||
else
|
||||
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
|
||||
echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ $distributionSha256Result = false ]; then
|
||||
echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2
|
||||
echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# unzip and move
|
||||
if command -v unzip >/dev/null; then
|
||||
unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip"
|
||||
else
|
||||
tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar"
|
||||
fi
|
||||
printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url"
|
||||
mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME"
|
||||
|
||||
clean || :
|
||||
exec_maven "$@"
|
||||
@@ -0,0 +1,149 @@
|
||||
<# : batch portion
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||
@REM or more contributor license agreements. See the NOTICE file
|
||||
@REM distributed with this work for additional information
|
||||
@REM regarding copyright ownership. The ASF licenses this file
|
||||
@REM to you under the Apache License, Version 2.0 (the
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@REM KIND, either express or implied. See the License for the
|
||||
@REM specific language governing permissions and limitations
|
||||
@REM under the License.
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Apache Maven Wrapper startup batch script, version 3.3.2
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM MVNW_REPOURL - repo url base for downloading maven distribution
|
||||
@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
|
||||
@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0)
|
||||
@SET __MVNW_CMD__=
|
||||
@SET __MVNW_ERROR__=
|
||||
@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
|
||||
@SET PSModulePath=
|
||||
@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
|
||||
IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
|
||||
)
|
||||
@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
|
||||
@SET __MVNW_PSMODULEP_SAVE=
|
||||
@SET __MVNW_ARG0_NAME__=
|
||||
@SET MVNW_USERNAME=
|
||||
@SET MVNW_PASSWORD=
|
||||
@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*)
|
||||
@echo Cannot start maven from wrapper >&2 && exit /b 1
|
||||
@GOTO :EOF
|
||||
: end batch / begin powershell #>
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
if ($env:MVNW_VERBOSE -eq "true") {
|
||||
$VerbosePreference = "Continue"
|
||||
}
|
||||
|
||||
# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
|
||||
$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
|
||||
if (!$distributionUrl) {
|
||||
Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
|
||||
}
|
||||
|
||||
switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {
|
||||
"maven-mvnd-*" {
|
||||
$USE_MVND = $true
|
||||
$distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
|
||||
$MVN_CMD = "mvnd.cmd"
|
||||
break
|
||||
}
|
||||
default {
|
||||
$USE_MVND = $false
|
||||
$MVN_CMD = $script -replace '^mvnw','mvn'
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
# apply MVNW_REPOURL and calculate MAVEN_HOME
|
||||
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
|
||||
if ($env:MVNW_REPOURL) {
|
||||
$MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" }
|
||||
$distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')"
|
||||
}
|
||||
$distributionUrlName = $distributionUrl -replace '^.*/',''
|
||||
$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
|
||||
$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain"
|
||||
if ($env:MAVEN_USER_HOME) {
|
||||
$MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain"
|
||||
}
|
||||
$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
|
||||
$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"
|
||||
|
||||
if (Test-Path -Path "$MAVEN_HOME" -PathType Container) {
|
||||
Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME"
|
||||
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
|
||||
exit $?
|
||||
}
|
||||
|
||||
if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {
|
||||
Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl"
|
||||
}
|
||||
|
||||
# prepare tmp dir
|
||||
$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile
|
||||
$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir"
|
||||
$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null
|
||||
trap {
|
||||
if ($TMP_DOWNLOAD_DIR.Exists) {
|
||||
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
|
||||
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
|
||||
}
|
||||
}
|
||||
|
||||
New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null
|
||||
|
||||
# Download and Install Apache Maven
|
||||
Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
|
||||
Write-Verbose "Downloading from: $distributionUrl"
|
||||
Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||
|
||||
$webclient = New-Object System.Net.WebClient
|
||||
if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
|
||||
$webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
|
||||
}
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
|
||||
|
||||
# If specified, validate the SHA-256 sum of the Maven distribution zip file
|
||||
$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
|
||||
if ($distributionSha256Sum) {
|
||||
if ($USE_MVND) {
|
||||
Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
|
||||
}
|
||||
Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
|
||||
if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
|
||||
Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property."
|
||||
}
|
||||
}
|
||||
|
||||
# unzip and move
|
||||
Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
|
||||
Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null
|
||||
try {
|
||||
Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
|
||||
} catch {
|
||||
if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
|
||||
Write-Error "fail to move MAVEN_HOME"
|
||||
}
|
||||
} finally {
|
||||
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
|
||||
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
|
||||
}
|
||||
|
||||
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
|
||||
@@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.4.3</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>myserver</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>myserver</name>
|
||||
<description>CC mini project</description>
|
||||
<url/>
|
||||
<licenses>
|
||||
<license/>
|
||||
</licenses>
|
||||
<developers>
|
||||
<developer/>
|
||||
</developers>
|
||||
<scm>
|
||||
<connection/>
|
||||
<developerConnection/>
|
||||
<tag/>
|
||||
<url/>
|
||||
</scm>
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<scope>runtime</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-api</artifactId>
|
||||
<version>0.11.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-impl</artifactId>
|
||||
<version>0.11.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-jackson</artifactId>
|
||||
<version>0.11.5</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.example.myserver;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
||||
|
||||
@SpringBootApplication
|
||||
public class MyserverApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(MyserverApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.example.myserver.configs;
|
||||
|
||||
import java.security.AuthProvider;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.crypto.bcrypt.BCrypt;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
|
||||
import com.example.myserver.repositories.UserRepository;
|
||||
|
||||
@Configuration
|
||||
public class ApplicationConfiguration {
|
||||
private final UserRepository userRepository;
|
||||
public ApplicationConfiguration(UserRepository userRepository){
|
||||
this.userRepository=userRepository;
|
||||
|
||||
}
|
||||
@Bean
|
||||
UserDetailsService userDetailsService() {
|
||||
return username -> userRepository.findByEmail(username)
|
||||
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
|
||||
}
|
||||
@Bean
|
||||
BCryptPasswordEncoder passwordEncoder(){
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception{
|
||||
return config.getAuthenticationManager();
|
||||
}
|
||||
|
||||
@Bean
|
||||
AuthenticationProvider authenticationProvider(){
|
||||
DaoAuthenticationProvider authprovider=new DaoAuthenticationProvider();
|
||||
authprovider.setUserDetailsService(userDetailsService());
|
||||
authprovider.setPasswordEncoder(passwordEncoder());
|
||||
return authprovider;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.example.myserver.configs;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
import org.springframework.web.servlet.HandlerExceptionResolver;
|
||||
|
||||
import com.example.myserver.services.JwtService;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
@Component
|
||||
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
|
||||
private final HandlerExceptionResolver handlerExceptionResolver;
|
||||
private JwtService jwtService;
|
||||
private UserDetailsService userDetailsService;
|
||||
|
||||
public JwtAuthenticationFilter(JwtService jwtService,UserDetailsService userDetailsService,HandlerExceptionResolver handlerExceptionResolver){
|
||||
|
||||
this.handlerExceptionResolver=handlerExceptionResolver;
|
||||
this.jwtService=jwtService;
|
||||
this.userDetailsService=userDetailsService;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
protected void doFilterInternal(
|
||||
@NonNull HttpServletRequest request,
|
||||
@NonNull HttpServletResponse response,
|
||||
@NonNull FilterChain filterChain) throws ServletException, IOException {
|
||||
final String authHeader=request.getHeader("Authorization");
|
||||
if (authHeader==null || !authHeader.startsWith("Bearer")){
|
||||
filterChain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final String userjwt=authHeader.substring(7);
|
||||
final String userEmail=jwtService.extractUsername(userjwt);
|
||||
Authentication authentication=SecurityContextHolder.getContext().getAuthentication();
|
||||
if(userEmail!=null && authentication==null){
|
||||
|
||||
UserDetails userDetails=this.userDetailsService.loadUserByUsername(userEmail);
|
||||
if (jwtService.isTokenValid(userjwt, userDetails)) {
|
||||
|
||||
UsernamePasswordAuthenticationToken authenticationToken=new UsernamePasswordAuthenticationToken(
|
||||
userDetails, null, userDetails.getAuthorities()
|
||||
);
|
||||
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
catch (Exception err) {
|
||||
handlerExceptionResolver.resolveException(request, response, null, err);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.example.myserver.configs;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
public class SecurityConfiguration {
|
||||
private final AuthenticationProvider authenticationProvider;
|
||||
private final JwtAuthenticationFilter jwtAuthenticationFilter;
|
||||
|
||||
public SecurityConfiguration(
|
||||
JwtAuthenticationFilter jwtAuthenticationFilter,
|
||||
AuthenticationProvider authenticationProvider
|
||||
) {
|
||||
this.authenticationProvider = authenticationProvider;
|
||||
this.jwtAuthenticationFilter = jwtAuthenticationFilter;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
http.csrf()
|
||||
.disable()
|
||||
.authorizeHttpRequests()
|
||||
.requestMatchers("/api/**")
|
||||
.permitAll()
|
||||
.anyRequest()
|
||||
.authenticated()
|
||||
.and()
|
||||
.sessionManagement()
|
||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
||||
.and()
|
||||
.authenticationProvider(authenticationProvider)
|
||||
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
CorsConfigurationSource corsConfigurationSource() {
|
||||
CorsConfiguration configuration = new CorsConfiguration();
|
||||
|
||||
configuration.setAllowedOrigins(List.of("*"));
|
||||
configuration.setAllowedMethods(List.of("GET","PUT","DELETE","POST"));
|
||||
configuration.setAllowedHeaders(List.of("Authorization","Content-Type"));
|
||||
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
|
||||
source.registerCorsConfiguration("/**",configuration);
|
||||
|
||||
return source;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.example.myserver.controllers;
|
||||
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.example.myserver.dtos.LoginUserDto;
|
||||
import com.example.myserver.dtos.RegisterUserDto;
|
||||
import com.example.myserver.models.User;
|
||||
import com.example.myserver.responses.LoginResponse;
|
||||
import com.example.myserver.services.AuthenticationService;
|
||||
import com.example.myserver.services.JwtService;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
|
||||
@RequestMapping("/api")
|
||||
@RestController
|
||||
public class AuthController {
|
||||
|
||||
private final JwtService jwtService;
|
||||
private AuthenticationService authenticationService;
|
||||
|
||||
public AuthController(JwtService jwtService,AuthenticationService authenticationService){
|
||||
this.jwtService=jwtService;
|
||||
this.authenticationService=authenticationService;
|
||||
}
|
||||
|
||||
@GetMapping("/test")
|
||||
public String teString(@RequestParam String param) {
|
||||
return new String();
|
||||
}
|
||||
|
||||
@PostMapping("/login")
|
||||
public ResponseEntity<LoginResponse> LoginController(@RequestBody LoginUserDto entity) {
|
||||
|
||||
User authenticatedUser=authenticationService.authenticate(entity);
|
||||
String jwtToken=jwtService.generateToken(authenticatedUser);
|
||||
|
||||
LoginResponse loginResponse=new LoginResponse().setToken(jwtToken).setExpiresIn(jwtService.getExpirtationTime());
|
||||
return ResponseEntity.ok(loginResponse);
|
||||
}
|
||||
|
||||
@PostMapping("/signup")
|
||||
public ResponseEntity<User> register(@RequestBody RegisterUserDto entity) {
|
||||
User registeredUser=authenticationService.signUp(entity);
|
||||
|
||||
|
||||
return ResponseEntity.ok(registeredUser);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.example.myserver.dtos;
|
||||
|
||||
|
||||
public class LoginUserDto {
|
||||
private String email;
|
||||
private String password;
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.example.myserver.dtos;
|
||||
|
||||
public class RegisterUserDto {
|
||||
|
||||
private String email;
|
||||
private String password;
|
||||
private String firstname;
|
||||
private String lastname;
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public RegisterUserDto setEmail(String email) {
|
||||
this.email = email;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public RegisterUserDto setPassword(String password) {
|
||||
this.password = password;
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
public String getFirstname() {
|
||||
return firstname;
|
||||
}
|
||||
|
||||
public RegisterUserDto setFirstname(String firstname) {
|
||||
this.firstname = firstname;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getLastname() {
|
||||
return lastname;
|
||||
}
|
||||
|
||||
public RegisterUserDto setLastname(String lastname) {
|
||||
this.lastname = lastname;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package com.example.myserver.models;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.annotations.CreationTimestamp;
|
||||
import org.hibernate.annotations.UpdateTimestamp;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
@Table(name = "users")
|
||||
@Entity
|
||||
public class User implements UserDetails {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(nullable = false)
|
||||
private Integer id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String username;
|
||||
|
||||
/*
|
||||
|
||||
//Optional feature might add later
|
||||
|
||||
@Column(name = "verification_code")
|
||||
private String verificationCode;
|
||||
|
||||
@Column(name ="verification_expiry")
|
||||
private LocalDateTime verificationExpiry;
|
||||
|
||||
*/
|
||||
|
||||
@Column(unique = true, nullable = false)
|
||||
private String email;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String password;
|
||||
|
||||
|
||||
|
||||
public User(){
|
||||
}
|
||||
|
||||
public User(String firstname,String lastname,String email,String password){
|
||||
this.username=firstname+lastname;
|
||||
this.email=email;
|
||||
this.password=password;
|
||||
}
|
||||
|
||||
|
||||
@CreationTimestamp
|
||||
@Column(updatable = false, name = "created_at")
|
||||
private Date createdAt;
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities(){
|
||||
return List.of();
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return email;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setFullname(String firstname,String lastname) {
|
||||
this.username=firstname+lastname;
|
||||
}
|
||||
|
||||
public String getFullname(String firstname,String lastname){
|
||||
return this.username;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public Date getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(Date createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.example.myserver.repositories;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import com.example.myserver.models.User;
|
||||
public interface UserRepository extends CrudRepository<User,Integer> {
|
||||
Optional<User> findByEmail(String email);
|
||||
/*
|
||||
// might use later
|
||||
Optional<User> findByVerificationCode(String verificationCode);
|
||||
*/
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.example.myserver.responses;
|
||||
|
||||
|
||||
public class LoginResponse {
|
||||
private String token;
|
||||
private long expiresIn;
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public LoginResponse setToken(String token) {
|
||||
this.token = token;
|
||||
return this;
|
||||
}
|
||||
|
||||
public long getExpiresIn() {
|
||||
return expiresIn;
|
||||
}
|
||||
|
||||
public LoginResponse setExpiresIn(long expiresIn) {
|
||||
this.expiresIn = expiresIn;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.example.myserver.services;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.example.myserver.dtos.LoginUserDto;
|
||||
import com.example.myserver.dtos.RegisterUserDto;
|
||||
import com.example.myserver.models.User;
|
||||
import com.example.myserver.repositories.UserRepository;
|
||||
|
||||
@Service
|
||||
public class AuthenticationService {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
private final AuthenticationManager authenticationManager;
|
||||
|
||||
public AuthenticationService( UserRepository userRepository, AuthenticationManager authenticationManager , PasswordEncoder passwordEncoder){
|
||||
this.userRepository=userRepository;
|
||||
this.passwordEncoder=passwordEncoder;
|
||||
this.authenticationManager=authenticationManager;
|
||||
}
|
||||
|
||||
public User signUp(RegisterUserDto inputuser){
|
||||
User user=new User(inputuser.getFirstname(),inputuser.getLastname(),inputuser.getEmail(),passwordEncoder.encode(inputuser.getPassword()));
|
||||
/*
|
||||
User user = new User()
|
||||
.setFullname(inputuser.getFirstname(),inputuser.getLastname())
|
||||
.setEmail(inputuser.getEmail())
|
||||
.setPassword(passwordEncoder.encode(inputuser.getPassword()));
|
||||
*/
|
||||
|
||||
return userRepository.save(user) ;
|
||||
}
|
||||
|
||||
public User authenticate(LoginUserDto inputuser){
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(inputuser.getEmail()
|
||||
, inputuser.getPassword()));
|
||||
return userRepository.findByEmail(inputuser.getEmail()).orElseThrow();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.example.myserver.services;
|
||||
|
||||
import java.security.Key;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import io.jsonwebtoken.io.Decoders;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
|
||||
@Service
|
||||
public class JwtService {
|
||||
@Value("${security.jwt.secret-key}")
|
||||
private String secretKey;
|
||||
|
||||
@Value("${security.jwt.expiration-time}")
|
||||
private long jwtExpiration;
|
||||
|
||||
public String extractUsername(String token){
|
||||
return extractClaim(token,Claims::getSubject);
|
||||
}
|
||||
|
||||
public <T> T extractClaim(String token,Function<Claims,T> claimsResolver){
|
||||
final Claims claims=extractAllClaims(token);
|
||||
return claimsResolver.apply(claims);
|
||||
|
||||
}
|
||||
|
||||
public String generateToken(UserDetails userDetails) {
|
||||
return generateToken(new HashMap<>(), userDetails);
|
||||
}
|
||||
|
||||
public String generateToken(Map<String, Object> extraClaims, UserDetails userDetails) {
|
||||
return buildToken(extraClaims, userDetails, jwtExpiration);
|
||||
}
|
||||
|
||||
public long getExpirtationTime(){
|
||||
return jwtExpiration;
|
||||
}
|
||||
private String buildToken(Map<String,Object> extraClaims,UserDetails userDetails,long expiration){
|
||||
|
||||
return Jwts.builder().setClaims(extraClaims).setSubject(userDetails.getUsername())
|
||||
.setIssuedAt(new Date(System.currentTimeMillis()))
|
||||
.setExpiration(new Date(System.currentTimeMillis() + expiration))
|
||||
.signWith(getSignInKey(), SignatureAlgorithm.HS256)
|
||||
.compact();
|
||||
}
|
||||
|
||||
public boolean isTokenValid(String token, UserDetails userDetails) {
|
||||
final String username = extractUsername(token);
|
||||
return (username.equals(userDetails.getUsername())) && !isTokenExpired(token);
|
||||
}
|
||||
|
||||
private boolean isTokenExpired(String token) {
|
||||
return extractExpiration(token).before(new Date());
|
||||
}
|
||||
|
||||
private Date extractExpiration(String token) {
|
||||
return extractClaim(token, Claims::getExpiration);
|
||||
}
|
||||
|
||||
private Claims extractAllClaims(String token) {
|
||||
return Jwts
|
||||
.parserBuilder()
|
||||
.setSigningKey(getSignInKey())
|
||||
.build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
}
|
||||
|
||||
private Key getSignInKey() {
|
||||
byte[] keyBytes = Decoders.BASE64.decode(secretKey);
|
||||
return Keys.hmacShaKeyFor(keyBytes);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
# spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
|
||||
|
||||
server.port=8081
|
||||
|
||||
security.jwt.secret-key=3cfa76ef14937c1c0ea519f8fc057a80fcd04a7420f8e8bcd0a7567c272e007b
|
||||
security.jwt.expiration-time=3600000
|
||||
|
||||
spring.datasource.url=jdbc:mysql://localhost:3306/drive?useSSL=false&serverTimezone=UTC
|
||||
spring.datasource.username=root
|
||||
spring.datasource.password=sqlsys
|
||||
|
||||
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||
spring.jpa.hibernate.ddl-auto=update
|
||||
spring.jpa.open-in-view=false
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.example.myserver;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
class MyserverApplicationTests {
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
package-lock.json
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
@@ -1,38 +0,0 @@
|
||||
import js from '@eslint/js'
|
||||
import globals from 'globals'
|
||||
import react from 'eslint-plugin-react'
|
||||
import reactHooks from 'eslint-plugin-react-hooks'
|
||||
import reactRefresh from 'eslint-plugin-react-refresh'
|
||||
|
||||
export default [
|
||||
{ ignores: ['dist'] },
|
||||
{
|
||||
files: ['**/*.{js,jsx}'],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
ecmaFeatures: { jsx: true },
|
||||
sourceType: 'module',
|
||||
},
|
||||
},
|
||||
settings: { react: { version: '18.3' } },
|
||||
plugins: {
|
||||
react,
|
||||
'react-hooks': reactHooks,
|
||||
'react-refresh': reactRefresh,
|
||||
},
|
||||
rules: {
|
||||
...js.configs.recommended.rules,
|
||||
...react.configs.recommended.rules,
|
||||
...react.configs['jsx-runtime'].rules,
|
||||
...reactHooks.configs.recommended.rules,
|
||||
'react/jsx-no-target-blank': 'off',
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
@@ -1,22 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/image.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link href="/src/styles.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/flowbite@3.1.2/dist/flowbite.min.css" rel="stylesheet" />
|
||||
|
||||
<title>Drive-thru</title>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script src="https://cdn.jsdelivr.net/npm/flowbite@3.1.2/dist/flowbite.min.js"></script>
|
||||
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.jsx"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,37 +0,0 @@
|
||||
{
|
||||
"name": "drive-thru",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@reduxjs/toolkit": "^2.6.0",
|
||||
"@tailwindcss/vite": "^4.0.9",
|
||||
"lucide-react": "^0.476.0",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-icons": "^5.5.0",
|
||||
"react-redux": "^9.2.0",
|
||||
"react-router-dom": "^7.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.21.0",
|
||||
"@types/react": "^19.0.10",
|
||||
"@types/react-dom": "^19.0.4",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"eslint": "^9.21.0",
|
||||
"eslint-plugin-react": "^7.37.4",
|
||||
"eslint-plugin-react-hooks": "^5.0.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.19",
|
||||
"globals": "^15.15.0",
|
||||
"postcss": "^8.5.3",
|
||||
"tailwindcss": "^4.0.9",
|
||||
"vite": "^6.2.0"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 144 KiB |
|
Before Width: | Height: | Size: 317 KiB |
|
Before Width: | Height: | Size: 332 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 48 KiB |
@@ -1,23 +0,0 @@
|
||||
import "./App.css";
|
||||
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
|
||||
import Login from "./pages/Authentication/Login";
|
||||
import SignUp from "./pages/Authentication/SignUp";
|
||||
import DrivethruLandingPage from "./pages/UserPages/DrivethruLandingPage";
|
||||
import Dashboard from "./pages/UserPages/Dashboard";
|
||||
import NotFoundPage from "./pages/UserPages/NotFoundPage";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<Router>
|
||||
<Routes>
|
||||
<Route path="/" element={<DrivethruLandingPage />} />
|
||||
<Route path="/login" element={<Login />} />
|
||||
<Route path="/signup" element={<SignUp />} />
|
||||
<Route path="/Dashboard" element={<Dashboard />} />
|
||||
<Route path="*" element={<NotFoundPage />} />
|
||||
</Routes>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -1,134 +0,0 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
const FileTable = ({ initialPath }) => {
|
||||
const [currentPath, setCurrentPath] = useState(initialPath || "/");
|
||||
const [files, setFiles] = useState([]);
|
||||
|
||||
// Helpers to parse entry
|
||||
const getType = (entry) =>
|
||||
entry.trim().startsWith("📁") ? "Folder" : "File";
|
||||
const getName = (entry) => entry.trim().replace(/^📁\s*|^📄\s*/, "");
|
||||
const isFile = (entry) => getType(entry) === "File";
|
||||
|
||||
// Fetch and show only top-level entries (indentation = 0)
|
||||
const fetchFiles = async () => {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`http://192.168.29.61:8080/api/hdfs/listFiles?hdfsPath=${currentPath}`
|
||||
);
|
||||
const data = await response.json();
|
||||
|
||||
// Filter entries: only those without leading spaces
|
||||
const filtered = data.filter(
|
||||
(entry) => entry.match(/^ */)[0].length === 0
|
||||
);
|
||||
setFiles(filtered);
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch files:", error);
|
||||
setFiles([]);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchFiles();
|
||||
}, [currentPath]);
|
||||
|
||||
// Navigate into a folder
|
||||
const handleOpenFolder = (folderName) => {
|
||||
const newPath =
|
||||
currentPath === "/" ? `/${folderName}` : `${currentPath}/${folderName}`;
|
||||
setCurrentPath(newPath);
|
||||
};
|
||||
|
||||
// Go up one level
|
||||
const goBack = () => {
|
||||
if (currentPath === "/") return;
|
||||
const parts = currentPath.split("/").filter(Boolean);
|
||||
parts.pop();
|
||||
setCurrentPath(parts.length === 0 ? "/" : `/${parts.join("/")}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative overflow-x-auto shadow-md rounded-lg">
|
||||
<div className="flex items-center justify-between px-6 py-4 bg-blue-100 text-black font-medium">
|
||||
<span>Path: {currentPath}</span>
|
||||
{currentPath !== "/" && (
|
||||
<button onClick={goBack} className="text-blue-600 hover:underline">
|
||||
⬅️ Go Back
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<table className="w-full text-sm text-left text-black">
|
||||
<thead className="text-xs text-black uppercase bg-blue-100">
|
||||
<tr>
|
||||
<th scope="col" className="px-6 py-3">
|
||||
File Name
|
||||
</th>
|
||||
<th scope="col" className="px-6 py-3">
|
||||
Type
|
||||
</th>
|
||||
<th scope="col" className="px-6 py-3">
|
||||
Action
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{files.length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan="3" className="px-6 py-4 text-gray-600">
|
||||
No files found.
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
files.map((entry, idx) => {
|
||||
const name = getName(entry);
|
||||
const type = getType(entry);
|
||||
const encodedPath = encodeURIComponent(`${currentPath}/${name}`);
|
||||
const downloadUrl = `http://192.168.29.61:8080/api/hdfs/downloadFile?hdfsPath=${encodedPath}&localPath=E:/testdownload/${name}&kalas=${
|
||||
currentPath.split("/")[1] || "user"
|
||||
}`;
|
||||
|
||||
return (
|
||||
<tr
|
||||
key={idx}
|
||||
className="even:bg-blue-50 odd:bg-white border-b border-blue-200"
|
||||
>
|
||||
<td className="px-6 py-4 font-medium whitespace-nowrap">
|
||||
{name}
|
||||
</td>
|
||||
<td className="px-6 py-4">{type}</td>
|
||||
<td className="px-6 py-4">
|
||||
{isFile(entry) ? (
|
||||
<a
|
||||
href={downloadUrl}
|
||||
className="font-medium text-blue-600 hover:underline"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Download
|
||||
</a>
|
||||
) : (
|
||||
<button
|
||||
onClick={() => handleOpenFolder(name)}
|
||||
className="font-medium text-blue-600 hover:underline"
|
||||
>
|
||||
Open
|
||||
</button>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
FileTable.propTypes = {
|
||||
initialPath: PropTypes.string,
|
||||
};
|
||||
|
||||
export default FileTable;
|
||||
@@ -1,68 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
import { uploadFileToHDFS } from "../utils/api";
|
||||
|
||||
const FileUpload = () => {
|
||||
const [file, setFile] = useState(null);
|
||||
const [hdfsPath, setHdfsPath] = useState("/kalas");
|
||||
const [uploadedFileName, setUploadedFileName] = useState("");
|
||||
const [username, setUsername] = useState("kalas");
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
if (!file || !uploadedFileName) {
|
||||
return;
|
||||
}
|
||||
uploadFileToHDFS(file, hdfsPath, uploadedFileName, username);
|
||||
};
|
||||
|
||||
return (
|
||||
<form
|
||||
onSubmit={handleSubmit}
|
||||
className="p-5 py-16 border rounded shadow w-full max-w-md"
|
||||
>
|
||||
<h2 className="text-lg font-bold mb-2">Upload File Your File</h2>
|
||||
|
||||
<input
|
||||
type="file"
|
||||
onChange={(e) => {
|
||||
setFile(e.target.files[0]);
|
||||
setUploadedFileName(e.target.files[0]?.name || "");
|
||||
}}
|
||||
className="mb-2"
|
||||
/>
|
||||
|
||||
{/* <input
|
||||
type="text"
|
||||
placeholder="HDFS Path"
|
||||
value={hdfsPath}
|
||||
onChange={(e) => setHdfsPath(e.target.value)}
|
||||
className="border p-2 mb-2 w-full"
|
||||
/> */}
|
||||
|
||||
{/* <input
|
||||
type="text"
|
||||
placeholder="Uploaded File Name"
|
||||
value={uploadedFileName}
|
||||
onChange={(e) => setUploadedFileName(e.target.value)}
|
||||
className="border p-2 mb-2 w-full"
|
||||
/> */}
|
||||
|
||||
{/* <input
|
||||
type="text"
|
||||
placeholder="Username"
|
||||
value={username}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
className="border p-2 mb-2 w-full"
|
||||
/> */}
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
className="bg-blue-600 text-white px-4 py-2 rounded"
|
||||
>
|
||||
Upload File
|
||||
</button>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
export default FileUpload;
|
||||
@@ -1,162 +0,0 @@
|
||||
import { useState } from "react";
|
||||
import {
|
||||
Facebook,
|
||||
Twitter,
|
||||
Instagram,
|
||||
Linkedin,
|
||||
Mail,
|
||||
Phone,
|
||||
MapPin,
|
||||
} from "lucide-react";
|
||||
|
||||
const Footer = () => {
|
||||
const [email, setEmail] = useState("");
|
||||
|
||||
//Currently storing user email in localstorage
|
||||
const handleSubscribe = () => {
|
||||
if (email.trim() !== "") {
|
||||
localStorage.setItem("subscribedEmail", email);
|
||||
alert("You have successfully subscribed!");
|
||||
setEmail("");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<footer className="bg-gradient-to-r from-[#4a7cbd] via-[#5b4fd3] to-[#9377ff] w-full pt-16 pb-8">
|
||||
<div className="container mx-auto px-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-8 mb-12">
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center">
|
||||
<div className="text-white mr-3">
|
||||
<svg
|
||||
className="w-10 h-10"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M12 2L2 12L12 22L22 12L12 2Z"
|
||||
stroke="currentColor"
|
||||
strokeWidth="3"
|
||||
fill="none"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="text-2xl font-bold text-white">Drive-thru</h3>
|
||||
</div>
|
||||
<p className="text-white/90">
|
||||
Your secure cloud storage solution for all your digital needs.
|
||||
</p>
|
||||
<div className="flex space-x-4">
|
||||
<a href="https://facebook.com" target="_blank" rel="noopener noreferrer">
|
||||
<Facebook className="w-5 h-5 text-white cursor-pointer hover:text-cyan-200 transition-all duration-200 transform hover:scale-110" />
|
||||
</a>
|
||||
<a href="https://twitter.com" target="_blank" rel="noopener noreferrer">
|
||||
<Twitter className="w-5 h-5 text-white cursor-pointer hover:text-cyan-200 transition-all duration-200 transform hover:scale-110" />
|
||||
</a>
|
||||
<a href="https://instagram.com" target="_blank" rel="noopener noreferrer">
|
||||
<Instagram className="w-5 h-5 text-white cursor-pointer hover:text-cyan-200 transition-all duration-200 transform hover:scale-110" />
|
||||
</a>
|
||||
<a href="https://linkedin.com" target="_blank" rel="noopener noreferrer">
|
||||
<Linkedin className="w-5 h-5 text-white cursor-pointer hover:text-cyan-200 transition-all duration-200 transform hover:scale-110" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Quick Links */}
|
||||
<div>
|
||||
<h4 className="font-semibold text-white mb-4">Quick Links</h4>
|
||||
<ul className="space-y-2">
|
||||
<li>
|
||||
<a
|
||||
href="#about"
|
||||
className="text-white/90 hover:text-white transition-all duration-200 hover:translate-x-1 inline-block"
|
||||
>
|
||||
About Us
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#features"
|
||||
className="text-white/90 hover:text-white transition-all duration-200 hover:translate-x-1 inline-block"
|
||||
>
|
||||
Features
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#howItWorks"
|
||||
className="text-white/90 hover:text-white transition-all duration-200 hover:translate-x-1 inline-block"
|
||||
>
|
||||
How It Works
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Contact Info */}
|
||||
<div>
|
||||
<h4 className="font-semibold text-white mb-4">Contact</h4>
|
||||
<ul className="space-y-2">
|
||||
<li className="flex items-center text-white/90 hover:text-white group transition-colors duration-200">
|
||||
<Mail className="w-4 h-4 mr-2 group-hover:text-cyan-200" />
|
||||
support@drivethru.com
|
||||
</li>
|
||||
<li className="flex items-center text-white/90 hover:text-white group transition-colors duration-200">
|
||||
<Phone className="w-4 h-4 mr-2 group-hover:text-cyan-200" />
|
||||
+91 3628206234
|
||||
</li>
|
||||
<li className="flex items-center text-white/90 hover:text-white group transition-colors duration-200">
|
||||
<MapPin className="w-4 h-4 mr-2 group-hover:text-cyan-200" />
|
||||
123 Cloud Street, Digital City
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Newsletter */}
|
||||
<div>
|
||||
<h4 className="font-semibold text-white mb-4">Stay Updated</h4>
|
||||
<p className="text-white/90 mb-4">
|
||||
Get exclusive tips, updates on new features, and special offers directly in your inbox.
|
||||
</p>
|
||||
<div className="space-y-4">
|
||||
<input
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
placeholder="Enter your email"
|
||||
className="w-full px-4 py-2 rounded-md bg-white/10 border border-white/20 text-white placeholder:text-white/50 focus:bg-white/20 transition-all duration-200 outline-none focus:ring-2 focus:ring-white/30"
|
||||
/>
|
||||
<button
|
||||
onClick={handleSubscribe}
|
||||
className="w-full px-4 py-2 rounded-md bg-white text-blue-600 font-medium hover:bg-opacity-90 transition-all duration-200 transform hover:scale-105"
|
||||
>
|
||||
Subscribe to Newsletter
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="h-px w-full bg-white/20 my-8" />
|
||||
|
||||
{/* Bottom Section */}
|
||||
<div className="flex flex-col md:flex-row justify-between items-center text-white/90 text-sm">
|
||||
<p>© {new Date().getFullYear()} Drive-Thru. All rights reserved.</p>
|
||||
<div className="flex gap-4 mt-4 md:mt-0">
|
||||
<a href="#" className="hover:text-white transition-all duration-200 hover:translate-x-1 inline-block">
|
||||
Privacy Policy
|
||||
</a>
|
||||
<a href="#" className="hover:text-white transition-all duration-200 hover:translate-x-1 inline-block">
|
||||
Terms of Service
|
||||
</a>
|
||||
<a href="#" className="hover:text-white transition-all duration-200 hover:translate-x-1 inline-block">
|
||||
Cookie Policy
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
|
||||
export default Footer;
|
||||
@@ -1,308 +0,0 @@
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
const Sidebar = () => {
|
||||
return (
|
||||
<>
|
||||
<nav className="fixed top-0 z-50 h-[60px] w-full bg-white border-b border-gray-200 ">
|
||||
<div className="p-[15px] h-full lg:px-5 lg:pl-3 ">
|
||||
<div className="flex h-full items-center justify-between">
|
||||
<div className="flex items-center justify-start rtl:justify-end">
|
||||
<button
|
||||
data-drawer-target="logo-sidebar"
|
||||
data-drawer-toggle="logo-sidebar"
|
||||
aria-controls="logo-sidebar"
|
||||
type="button"
|
||||
className="inline-flex items-center p-2 text-lg text-white rounded-lg sm:hidden hover:bg-[#37A0EA] focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-[#37A0EA] dark:focus:ring-gray-600"
|
||||
>
|
||||
<span className="sr-only">Open sidebar</span>
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
aria-hidden="true"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
clipRule="evenodd"
|
||||
fillRule="evenodd"
|
||||
d="M2 4.75A.75.75 0 012.75 4h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 4.75zm0 10.5a.75.75 0 01.75-.75h7.5a.75.75 0 010 1.5h-7.5a.75.75 0 01-.75-.75zM2 10a.75.75 0 01.75-.75h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 10z"
|
||||
></path>
|
||||
</svg>
|
||||
</button>
|
||||
<Link to="/" className="flex ms-2 md:me-24">
|
||||
<img
|
||||
src="./image.png"
|
||||
className="h-8 me-3"
|
||||
alt="Drive-thru Logo"
|
||||
/>
|
||||
<span className="self-center text-xl font-semibold sm:text-2xl whitespace-nowrap dark:text-white">
|
||||
Drive-thru
|
||||
</span>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center">
|
||||
{" "}
|
||||
<div className="flex items-center justify-end mr-40 ">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search..."
|
||||
className="w-full border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="ml-2 px-4 py-2 text-white bg-blue-500 rounded-lg hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
>
|
||||
Search
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex items-center ms-3">
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
className="flex text-lg bg-gray-800 rounded-full focus:ring-4 focus:ring-gray-300 dark:focus:ring-gray-600"
|
||||
aria-expanded="false"
|
||||
data-dropdown-toggle="dropdown-user"
|
||||
>
|
||||
<span className="sr-only">Open user menu</span>
|
||||
<img
|
||||
className="w-8 h-8 rounded-full"
|
||||
src="https://flowbite.com/docs/images/people/profile-picture-5.jpg"
|
||||
alt="user photo"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
className="z-50 hidden my-4 text-base list-none bg-[#1877F2] divide-y divide-gray-100 rounded-sm shadow-sm dark:bg-gray-700 dark:divide-gray-600"
|
||||
id="dropdown-user"
|
||||
>
|
||||
<div className="px-4 py-3" role="none">
|
||||
<p
|
||||
className="text-lg text-white dark:text-white"
|
||||
role="none"
|
||||
>
|
||||
Neil Sims
|
||||
</p>
|
||||
<p
|
||||
className="text-lg font-medium text-white truncate dark:text-gray-300"
|
||||
role="none"
|
||||
>
|
||||
Drive-thru@Drive-thru.com
|
||||
</p>
|
||||
</div>
|
||||
<ul className="py-1" role="none">
|
||||
<li>
|
||||
<Link
|
||||
to="#"
|
||||
className="block px-4 py-2 text-lg text-white hover:bg-[#37A0EA] dark:text-gray-300 dark:hover:bg-[#37A0EA] dark:hover:text-white"
|
||||
role="menuitem"
|
||||
>
|
||||
Dashboard
|
||||
</Link>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<Link
|
||||
to="#"
|
||||
className="block px-4 py-2 text-lg text-white hover:bg-[#37A0EA] dark:text-gray-300 dark:hover:bg-[##37A0EA] dark:hover:text-white"
|
||||
role="menuitem"
|
||||
>
|
||||
Settings
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
to="#"
|
||||
className="block px-4 py-2 text-lg text-white hover:bg-[#37A0EA] dark:text-gray-300 dark:hover:bg-[#37A0EA] dark:hover:text-white"
|
||||
role="menuitem"
|
||||
>
|
||||
Earnings
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
to="#"
|
||||
className="block px-4 py-2 text-lg text-white hover:bg-[#37A0EA] dark:text-gray-300 dark:hover:bg-[#37A0EA] dark:hover:text-white"
|
||||
role="menuitem"
|
||||
>
|
||||
Sign out
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<aside
|
||||
id="logo-sidebar"
|
||||
className="fixed top-0 left-0 z-40 w-64 h-screen pt-[60px] transition-transform -translate-x-full bg-[##1877F2] border-r border-gray-200 sm:translate-x-0 dark:bg-[#1877F2] dark:border-gray-700"
|
||||
aria-label="Sidebar"
|
||||
>
|
||||
<div className="h-full px-3 pb-4 overflow-y-auto bg-[#1877F2] dark:bg-[#1877F2] custom-scrollbar">
|
||||
<ul className="space-y-2 font-medium">
|
||||
<li>
|
||||
<Link
|
||||
to="#"
|
||||
className="flex items-center p-2 mt-5 pt-4 pb-4 text-white rounded-lg dark:text-white hover:bg-[#37A0EA] dark:hover:bg-[#37A0EA] group"
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5 text-white transition duration-75 dark:text-gray-400 group-hover:text-white dark:group-hover:text-white"
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.62L12 2 9.19 8.62 2 9.24l5.46 4.73L5.82 21z" />
|
||||
</svg>
|
||||
|
||||
<span className="ms-3">Starred</span>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
to="#"
|
||||
className="flex items-center p-2 pt-4 pb-4 text-white rounded-lg dark:text-white hover:bg-[#37A0EA] dark:hover:bg-[#37A0EA] group"
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
viewBox="0 0 20 17"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M2.31763 16.0834C1.93846 16.0834 1.60669 15.9372 1.32231 15.6449C1.03794 15.3527 0.895752 15.0248 0.895752 14.6615V2.33856C0.895752 1.97519 1.03794 1.64737 1.32231 1.3551C1.60669 1.06282 1.93846 0.916687 2.31763 0.916687H8.97674L10.3986 2.33856H18.4322C18.7956 2.33856 19.1234 2.4847 19.4157 2.77697C19.7079 3.06925 19.8541 3.39707 19.8541 3.76044V14.6615C19.8541 15.0248 19.7079 15.3527 19.4157 15.6449C19.1234 15.9372 18.7956 16.0834 18.4322 16.0834H2.31763ZM9.4033 13.0026H16.9866V12.5524C16.9866 11.8888 16.6509 11.3477 15.9795 10.9291C15.308 10.5104 14.3799 10.3011 13.195 10.3011C12.0101 10.3011 11.0819 10.5104 10.4105 10.9291C9.73903 11.3477 9.4033 11.8888 9.4033 12.5524V13.0026ZM13.195 8.87919C13.6689 8.87919 14.0757 8.70935 14.4154 8.36968C14.7551 8.03001 14.9249 7.6232 14.9249 7.14924C14.9249 6.67528 14.7551 6.26847 14.4154 5.9288C14.0757 5.58913 13.6689 5.41929 13.195 5.41929C12.721 5.41929 12.3142 5.58913 11.9745 5.9288C11.6349 6.26847 11.465 6.67528 11.465 7.14924C11.465 7.6232 11.6349 8.03001 11.9745 8.36968C12.3142 8.70935 12.721 8.87919 13.195 8.87919Z"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<span className="flex-1 ms-3 whitespace-nowrap">
|
||||
Shared with me
|
||||
</span>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
to="#"
|
||||
className="flex items-center p-2 pt-4 pb-4 text-white rounded-lg dark:text-white hover:bg-[#37A0EA] dark:hover:bg-[#37A0EA] group"
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M5 3h2v18H5V3zm6 6h2v12h-2V9zm6-4h2v16h-2V5z" />
|
||||
</svg>
|
||||
|
||||
<span className="flex-1 ms-3 whitespace-nowrap">
|
||||
Statistics
|
||||
</span>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
to="#"
|
||||
className="flex items-center p-2 pt-4 pb-4 text-white rounded-lg dark:text-white hover:bg-[#37A0EA] dark:hover:bg-[#37A0EA] group"
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5 text-white dark:text-white"
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M3 6a2 2 0 0 1 2-2h5.532a2 2 0 0 1 1.536.72l1.9 2.28H3V6Zm0 3v10a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V9H3Z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<span className="flex-1 ms-3 whitespace-nowrap">My files</span>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
to="#"
|
||||
className="flex items-center p-2 pt-4 pb-4 text-white rounded-lg dark:text-white hover:bg-[#37A0EA] dark:hover:bg-[#37A0EA] group"
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
viewBox="0 0 20 19"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M8.19471 18.9791L7.72075 15.9932C7.42058 15.8826 7.10461 15.7325 6.77284 15.5429C6.44106 15.3534 6.14879 15.1559 5.89601 14.9505L3.09966 16.2302L0.895752 12.3437L3.45513 10.4716C3.42353 10.3294 3.40378 10.1675 3.39588 9.98579C3.38798 9.8041 3.38403 9.64217 3.38403 9.49998C3.38403 9.35779 3.38798 9.19586 3.39588 9.01417C3.40378 8.83249 3.42353 8.67055 3.45513 8.52837L0.895752 6.65623L3.09966 2.76977L5.89601 4.04946C6.14879 3.84408 6.44106 3.64659 6.77284 3.45701C7.10461 3.26743 7.42058 3.12524 7.72075 3.03045L8.19471 0.020813H12.5551L13.0291 3.00675C13.3293 3.11734 13.6492 3.26348 13.9889 3.44516C14.3285 3.62685 14.6168 3.82828 14.8538 4.04946L17.6502 2.76977L19.8541 6.65623L17.2947 8.48097C17.3263 8.63896 17.3461 8.80879 17.354 8.99048C17.3619 9.17216 17.3658 9.34199 17.3658 9.49998C17.3658 9.65797 17.3619 9.82385 17.354 9.99764C17.3461 10.1714 17.3263 10.3373 17.2947 10.4953L19.8541 12.3437L17.6502 16.2302L14.8538 14.9505C14.601 15.1559 14.3127 15.3573 13.9889 15.5548C13.665 15.7523 13.3451 15.8984 13.0291 15.9932L12.5551 18.9791H8.19471ZM10.3749 12.5807C11.228 12.5807 11.9548 12.2805 12.5551 11.6802C13.1555 11.0798 13.4556 10.3531 13.4556 9.49998C13.4556 8.64686 13.1555 7.92012 12.5551 7.31977C11.9548 6.71942 11.228 6.41925 10.3749 6.41925C9.52179 6.41925 8.79506 6.71942 8.19471 7.31977C7.59436 7.92012 7.29419 8.64686 7.29419 9.49998C7.29419 10.3531 7.59436 11.0798 8.19471 11.6802C8.79506 12.2805 9.52179 12.5807 10.3749 12.5807Z"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<span className="flex-1 ms-3 whitespace-nowrap">Settings</span>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
to="#"
|
||||
className="flex items-center p-2 pt-4 pb-4 text-white rounded-lg dark:text-white hover:bg-[#37A0EA] dark:hover:bg-[#37A0EA] group"
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5 text-white dark:text-white self-center"
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M8.586 2.586A2 2 0 0 1 10 2h4a2 2 0 0 1 2 2v2h3a1 1 0 1 1 0 2v12a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V8a1 1 0 0 1 0-2h3V4a2 2 0 0 1 .586-1.414ZM10 6h4V4h-4v2Zm1 4a1 1 0 1 0-2 0v8a1 1 0 1 0 2 0v-8Zm4 0a1 1 0 1 0-2 0v8a1 1 0 1 0 2 0v-8Z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<span className="flex-1 ms-3 whitespace-nowrap">Trash</span>
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
<div className="mt-6 p-4 rounded-lg text-white">
|
||||
{/* Cloud Icon + Title */}
|
||||
<div className="flex items-center">
|
||||
<svg
|
||||
className="w-7 h-7 text-white dark:text-white"
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path d="M13.383 4.076a6.5 6.5 0 0 0-6.887 3.95A5 5 0 0 0 7 18h3v-4a2 2 0 0 1-1.414-3.414l2-2a2 2 0 0 1 2.828 0l2 2A2 2 0 0 1 14 14v4h4a4 4 0 0 0 .988-7.876 6.5 6.5 0 0 0-5.605-6.048Z" />
|
||||
<path d="M12.707 9.293a1 1 0 0 0-1.414 0l-2 2a1 1 0 1 0 1.414 1.414l.293-.293V19a1 1 0 1 0 2 0v-6.586l.293.293a1 1 0 0 0 1.414-1.414l-2-2Z" />
|
||||
</svg>
|
||||
|
||||
<span className="ml-2 font-semibold">My Storage</span>
|
||||
</div>
|
||||
{/* Usage Text & Progress Bar */}
|
||||
<p className="mt-2 text-lg">Used: of 100GB</p>
|
||||
<div className="w-full bg-white rounded-full h-2 mt-2">
|
||||
<div
|
||||
className="bg-blue-500 h-2 rounded-full"
|
||||
style={{ width: "24%" }}
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Sidebar;
|
||||
@@ -1,28 +0,0 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
/* For WebKit-based browsers */
|
||||
.custom-scrollbar::-webkit-scrollbar {
|
||||
width: 15px;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
/* or a color of your choice */
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||||
background-color: #a0aec0;
|
||||
/* Customize thumb color */
|
||||
border-radius: 4px;
|
||||
border: 2px solid transparent;
|
||||
/* Optional: creates padding around thumb */
|
||||
background-clip: content-box;
|
||||
}
|
||||
|
||||
/* For Firefox */
|
||||
.custom-scrollbar {
|
||||
scrollbar-width: auto;
|
||||
/* "auto" or "thin" */
|
||||
scrollbar-color: #37A0EA transparent;
|
||||
/* thumb and track colors */
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import "./index.css";
|
||||
import App from "./App.jsx";
|
||||
|
||||
createRoot(document.getElementById("root")).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</StrictMode>
|
||||
);
|
||||
@@ -1,73 +0,0 @@
|
||||
import React from "react";
|
||||
import { FiEye, FiEyeOff } from "react-icons/fi";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
const Login = () => {
|
||||
const [showPassword, setShowPassword] = React.useState(false);
|
||||
|
||||
const togglePassword = () => {
|
||||
setShowPassword(!showPassword);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-100 flex items-center justify-center p-4">
|
||||
<div className="w-full max-w-md bg-white rounded-4xl shadow-lg p-8">
|
||||
<h1 className="text-2xl font-bold mb-6 text-gray-900 text-center">
|
||||
Log in
|
||||
</h1>
|
||||
|
||||
<div className="mb-4">
|
||||
<div className="flex items-center">
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
placeholder="Enter your email"
|
||||
className="w-full border border-gray-300 rounded-l-lg px-4 py-4 focus:outline-none focus:border-blue-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-1">
|
||||
<div className="relative">
|
||||
<input
|
||||
type={showPassword ? "text" : "password"}
|
||||
id="password"
|
||||
placeholder="Enter your password"
|
||||
className="w-full border border-gray-300 rounded-lg px-4 py-4 focus:outline-none focus:border-blue-500 pr-10"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={togglePassword}
|
||||
className="absolute right-2 top-4 text-2xl text-gray-500 hover:text-gray-700"
|
||||
>
|
||||
{showPassword ? <FiEyeOff /> : <FiEye />}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-6 ">
|
||||
<Link
|
||||
to="#!"
|
||||
className="text-sm text-blue-600 hover:underline inline-block"
|
||||
>
|
||||
Forgot password?
|
||||
</Link>
|
||||
</div>
|
||||
<button className="w-full py-3 bg-gradient-to-r from-[#1877F2] to-[#0E458C] hover:from-[#0E458C] hover:to-[#1877F2] text-white font-semibold rounded-full shadow-md transition duration-300">
|
||||
Login
|
||||
</button>
|
||||
<div className="text-center mt-6">
|
||||
<p className="text-gray-700">
|
||||
Don’t have an account?{" "}
|
||||
<Link
|
||||
to="/signup"
|
||||
className="text-emerald-500 hover:underline font-medium"
|
||||
>
|
||||
Sign up
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Login;
|
||||
@@ -1,86 +0,0 @@
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
import React, { useState } from "react";
|
||||
import { FiEye, FiEyeOff } from "react-icons/fi";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
const SignUp = () => {
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-100 flex items-center justify-center p-6">
|
||||
<div className="w-full max-w-md bg-white rounded-2xl shadow-lg p-8">
|
||||
<h1 className="text-2xl font-bold text-gray-900 mb-6">Sign Up</h1>
|
||||
|
||||
{/* Form Fields */}
|
||||
<div className="space-y-4">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="First Name"
|
||||
className="w-full border border-gray-300 rounded-lg px-4 py-4 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Last Name"
|
||||
className="w-full border border-gray-300 rounded-lg px-4 py-4 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
<input
|
||||
type="email"
|
||||
placeholder="Enter your email"
|
||||
className="w-full border border-gray-300 rounded-lg px-4 py-4 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
|
||||
{/* Password Field */}
|
||||
<div className="relative">
|
||||
<input
|
||||
type={showPassword ? "text" : "password"}
|
||||
placeholder="Enter your password"
|
||||
className="w-full border border-gray-300 rounded-lg px-4 py-4 focus:outline-none focus:ring-2 focus:ring-blue-500 pr-10"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowPassword(!showPassword)}
|
||||
className="absolute right-3 top-4 text-2xl text-gray-500 hover:text-gray-700"
|
||||
>
|
||||
{showPassword ? <FiEyeOff /> : <FiEye />}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Confirm Password Field */}
|
||||
<div className="relative">
|
||||
<input
|
||||
type={showConfirmPassword ? "text" : "password"}
|
||||
placeholder="Confirm your password"
|
||||
className="w-full border border-gray-300 rounded-lg px-4 py-4 focus:outline-none focus:ring-2 focus:ring-blue-500 pr-10"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowConfirmPassword(!showConfirmPassword)}
|
||||
className="absolute right-3 top-4 text-2xl text-gray-500 hover:text-gray-700"
|
||||
>
|
||||
{showConfirmPassword ? <FiEyeOff /> : <FiEye />}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Sign Up Button */}
|
||||
<button className="w-full mt-6 py-3 bg-gradient-to-r from-[#10B981] to-[#07533A] hover:from-[#0E458C] hover:to-[#1877F2] text-white font-semibold rounded-lg shadow-md transition duration-300">
|
||||
Sign Up
|
||||
</button>
|
||||
|
||||
{/* Redirect to Login */}
|
||||
<p className="text-center mt-4 text-gray-700">
|
||||
Already have an account?{" "}
|
||||
<Link
|
||||
to="/login"
|
||||
className="text-blue-500 hover:underline font-medium"
|
||||
>
|
||||
Login
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SignUp;
|
||||
@@ -1,287 +0,0 @@
|
||||
import React from "react";
|
||||
import Footer from "../components/Footer";
|
||||
{
|
||||
/* <img src="vector.png" alt="" className="h-100" /> */
|
||||
}
|
||||
|
||||
const DrivethruLandingPage = () => {
|
||||
return (
|
||||
<div className="min-h-screen bg-white overflow-hidden">
|
||||
<div className="bg-white min-h-screen flex items-center relative">
|
||||
<div className="container mx-auto px-6 relative z-10">
|
||||
<div className="flex flex-col md:flex-row items-center">
|
||||
<div className="hidden md:block md:w-1/2 lg:w-3/5"></div>
|
||||
|
||||
<div className="w-full mt-70 md:w-1/2 lg:w-2/5 max-w-lg bg-transparent">
|
||||
<div className="flex items-center mb-8">
|
||||
<div className="text-cyan-400 mr-3">
|
||||
<svg
|
||||
className="w-12 h-12"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M12 2L2 12L12 22L22 12L12 2Z"
|
||||
stroke="currentColor"
|
||||
strokeWidth="3"
|
||||
fill="none"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<h1 className="text-5xl font-bold text-black">Drive-thru</h1>
|
||||
</div>
|
||||
|
||||
<h2 className="text-2xl font-bold mb-6 text-black">
|
||||
Store, Access & Share Your Files — Anytime, Anywhere!
|
||||
</h2>
|
||||
|
||||
<p className="text-gray-800 mb-10 text-lg">
|
||||
A simple, secure, and fast cloud storage solution for all your
|
||||
files. Upload, organize, and access with ease.
|
||||
</p>
|
||||
|
||||
<div className="flex flex-row space-x-4">
|
||||
<button className="px-6 py-3 bg-emerald-500 hover:bg-emerald-600 text-white font-medium rounded-full transition-colors duration-200 shadow-md">
|
||||
Get Started
|
||||
</button>
|
||||
<button className="px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-full transition-colors duration-200 shadow-md">
|
||||
Login
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-white py-16">
|
||||
<div className="container mx-auto px-6">
|
||||
<div className="flex flex-col md:flex-row items-center justify-between mb-24">
|
||||
{" "}
|
||||
<div className="w-full md:w-1/2 lg:w-2/5 flex justify-center md:justify-end">
|
||||
<img
|
||||
src="./He.png"
|
||||
alt="Person using Drive-thru on laptop"
|
||||
className="mx h-auto max-w-full"
|
||||
/>
|
||||
</div>
|
||||
{/* Features Card */}
|
||||
<div className="w-full md:w-1/2 lg:w-3/5 mb-12 md:mb-0">
|
||||
<div className="bg-blue-100 rounded-3xl p-8 md:p-10 shadow-lg">
|
||||
<h2 className="text-3xl font-bold mb-8">Key Features</h2>
|
||||
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-start">
|
||||
<div className="text-emerald-500 mr-3 mt-1">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M9 19l3 3m0 0l3-3m-3 3V10"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<p className="text-lg font-semibold">
|
||||
"Easy Upload & Access" – Drag & drop, instant access.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start">
|
||||
<div className="text-emerald-500 mr-3 mt-1">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<p className="text-lg font-semibold">
|
||||
"Secure & Private" – End-to-end encryption.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start">
|
||||
<div className="text-emerald-500 mr-3 mt-1">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<p className="text-lg font-semibold">
|
||||
"Seamless Sharing" – Share files with one click.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start">
|
||||
<div className="text-emerald-500 mr-3 mt-1">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h.5A2.5 2.5 0 0020 5.5v-1.65"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<p className="text-lg font-semibold">
|
||||
"Access Anywhere" – Works on all devices.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* How It Works Section */}
|
||||
<div className="flex flex-col md:flex-row-reverse items-center justify-between">
|
||||
{/* Person with Phone Image */}
|
||||
<div className="w-full md:w-1/2 lg:w-2/5 mb-12 md:mb-0 flex justify-center md:justify-start">
|
||||
<img
|
||||
src="./She.png"
|
||||
alt="Person using Drive-thru on phone"
|
||||
className="h-auto max-w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* How It Works Card */}
|
||||
<div className="w-full md:w-1/2 lg:w-3/5">
|
||||
<div className="bg-blue-100 rounded-3xl p-8 md:p-10 shadow-lg">
|
||||
<h2 className="text-3xl font-bold mb-8">How It Works</h2>
|
||||
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-start">
|
||||
<div className="text-emerald-500 mr-3 mt-1">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<p className="text-lg font-semibold">
|
||||
Create an account – Sign up in seconds.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start">
|
||||
<div className="text-emerald-500 mr-3 mt-1">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<p className="text-lg font-semibold">
|
||||
Upload files – Drag & drop or select from your device.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start">
|
||||
<div className="text-emerald-500 mr-3 mt-1">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"
|
||||
></path>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<p className="text-lg font-semibold">
|
||||
Manage files – Rename, move, or delete easily.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start">
|
||||
<div className="text-emerald-500 mr-3 mt-1">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<p className="text-lg font-semibold">
|
||||
Access anytime – Open files from any device.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Footer></Footer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DrivethruLandingPage;
|
||||
@@ -1,111 +0,0 @@
|
||||
import React from "react";
|
||||
import Sidebar from "../../components/Sidebar";
|
||||
import FileList from "../../components/FileList";
|
||||
import FileUpload from "../../components/FileUpload";
|
||||
import { FiPlus } from "react-icons/fi";
|
||||
|
||||
const Dashboard = () => {
|
||||
const [files, setFiles] = React.useState([]);
|
||||
|
||||
React.useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
const response = await fetch(
|
||||
"http://192.168.29.61:8080/api/hdfs/listFiles?hdfsPath=/"
|
||||
);
|
||||
const data = await response.json();
|
||||
setFiles(data);
|
||||
};
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* <!-- Main modal --> */}
|
||||
<div
|
||||
id="static-modal"
|
||||
data-modal-backdrop="static"
|
||||
tabindex="-1"
|
||||
aria-hidden="true"
|
||||
class="hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full"
|
||||
>
|
||||
<div class="relative p-4 w-full max-w-170 h-150 flex items-center justify-center">
|
||||
{/* <!-- Modal content --> */}
|
||||
<div class="relative bg-white rounded-lg shadow-sm ">
|
||||
{/* <!-- Modal header --> */}
|
||||
<div class="flex items-center justify-between p-2 md:p-5 rounded-t dark:border-gray-600 border-gray-200">
|
||||
<h3 class="text-xl font-semibold text-gray-900 dark:text-white">
|
||||
Static modal
|
||||
</h3>
|
||||
<button
|
||||
type="button"
|
||||
class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:hover:bg-gray-600 dark:hover:text-white"
|
||||
data-modal-hide="static-modal"
|
||||
>
|
||||
<svg
|
||||
class="w-3 h-3"
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 14 14"
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"
|
||||
/>
|
||||
</svg>
|
||||
<span class="sr-only">Close modal</span>
|
||||
</button>
|
||||
</div>
|
||||
{/* <!-- Modal body --> */}
|
||||
<div class="p-4 md:p-5 space-y-4">
|
||||
<FileUpload />
|
||||
</div>
|
||||
{/* <!-- Modal footer --> */}
|
||||
{/* <div class="flex items-center p-4 md:p-5 border-t border-gray-200 rounded-b ">
|
||||
<button
|
||||
data-modal-hide="static-modal"
|
||||
type="button"
|
||||
class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800"
|
||||
>
|
||||
I accept
|
||||
</button>
|
||||
<button
|
||||
data-modal-hide="static-modal"
|
||||
type="button"
|
||||
class="py-2.5 px-5 ms-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-lg border border-gray-200 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
|
||||
>
|
||||
Decline
|
||||
</button>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Sidebar />
|
||||
<div className="p-4 sm:ml-64">
|
||||
<div className="p-4 border-2 border-gray-200 border-dashed rounded-lg mt-14">
|
||||
<div className="w-full flex justify-between items-center">
|
||||
<h1 className="text-2xl font-bold mb-4">Dashboard</h1>
|
||||
<button
|
||||
data-modal-target="static-modal"
|
||||
data-modal-toggle="static-modal"
|
||||
class="block text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-3 py-2 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800"
|
||||
type="button"
|
||||
>
|
||||
<FiPlus className="text-2xl" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<FileList files={files}></FileList>
|
||||
<section className="w-full flex justify-end items-center min-h-160">
|
||||
{/* <!-- Modal toggle --> */}
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Dashboard;
|
||||
@@ -1,376 +0,0 @@
|
||||
import Footer from "../../components/Footer";
|
||||
import React from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
const DrivethruLandingPage = () => {
|
||||
const features = [
|
||||
{
|
||||
title: "Easy Upload & Access",
|
||||
description: "Drag & drop, instant access.",
|
||||
icon: (
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M9 19l3 3m0 0l3-3m-3 3V10"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Secure & Private",
|
||||
description: "End-to-end encryption.",
|
||||
icon: (
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Seamless Sharing",
|
||||
description: "Share files with one click.",
|
||||
icon: (
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Access Anywhere",
|
||||
description: "Works on all devices.",
|
||||
icon: (
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h.5A2.5 2.5 0 0020 5.5v-1.65"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const howItWorks = [
|
||||
{
|
||||
title: "Create an account",
|
||||
description: "Sign up in seconds.",
|
||||
icon: (
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Upload files",
|
||||
description: "Drag & drop or select from your device.",
|
||||
icon: (
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Manage files",
|
||||
description: "Rename, move, or delete easily.",
|
||||
icon: (
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"
|
||||
/>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Access anytime",
|
||||
description: "Open files from any device.",
|
||||
icon: (
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
// UseEffect and handle....click function to handle set and handle the animation of features..
|
||||
const [activeIndex, setActiveIndex] = useState(0);
|
||||
const [isPaused, setIsPaused] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isPaused) {
|
||||
const interval = setInterval(() => {
|
||||
setActiveIndex((prevIndex) => (prevIndex + 1) % features.length);
|
||||
}, 3000);
|
||||
return () => clearInterval(interval);
|
||||
}
|
||||
}, [isPaused, features.length]);
|
||||
|
||||
// Handle user interaction
|
||||
const handleFeatureClick = (index) => {
|
||||
setActiveIndex(index);
|
||||
setIsPaused(true);
|
||||
setTimeout(() => setIsPaused(false), 1000);
|
||||
};
|
||||
|
||||
const [activeIndex1, setActiveIndex1] = useState(0);
|
||||
const [isPaused1, setIsPaused1] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isPaused1) {
|
||||
const interval = setInterval(() => {
|
||||
setActiveIndex1((prevIndex) => (prevIndex + 1) % howItWorks.length);
|
||||
}, 3000);
|
||||
return () => clearInterval(interval);
|
||||
}
|
||||
}, [isPaused1, howItWorks.length]);
|
||||
|
||||
const handleFeatureClick1 = (index) => {
|
||||
setActiveIndex1(index);
|
||||
setIsPaused1(true);
|
||||
setTimeout(() => setIsPaused1(false), 1000);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen overflow-x-hidden bg-white">
|
||||
{/* Hero Section */}
|
||||
<div
|
||||
id="about"
|
||||
className="bg-gradient-to-r from-blue-50 to-white min-h-[90vh] flex items-center relative"
|
||||
>
|
||||
<div className="container mx-auto px-4 md:px-6 lg:px-8 relative z-10">
|
||||
<div className="flex flex-col md:flex-row items-center gap-8 lg:gap-12">
|
||||
{/* Left Side - Text Content */}
|
||||
<div className="w-full md:w-1/2 text-center md:text-left order-1 md:order-1">
|
||||
<div className="flex justify-center md:justify-start items-center mb-6 lg:mb-8">
|
||||
<div className="text-cyan-400 mr-2 md:mr-3">
|
||||
<svg
|
||||
className="w-10 md:w-12 h-10 md:h-12"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M12 2L2 12L12 22L22 12L12 2Z"
|
||||
stroke="currentColor"
|
||||
strokeWidth="3"
|
||||
fill="none"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<h1 className="text-4xl md:text-5xl font-bold text-black">
|
||||
Drive-thru
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<h2 className="text-xl md:text-2xl font-bold mb-4 md:mb-6 text-black">
|
||||
Store, Access & Share Your Files — Anytime, Anywhere!
|
||||
</h2>
|
||||
|
||||
<p className="text-gray-800 mb-6 md:mb-10 text-base md:text-lg">
|
||||
A simple, secure, and fast cloud storage solution for all your
|
||||
files. Upload, organize, and access with ease.
|
||||
</p>
|
||||
|
||||
{/* Buttons */}
|
||||
<div className="flex flex-col sm:flex-row justify-center md:justify-start space-y-4 sm:space-y-0 sm:space-x-4">
|
||||
<Link
|
||||
to="/signup"
|
||||
className="bg-emerald-500 hover:bg-emerald-600 text-white font-medium rounded-full px-6 py-4 md:px-8 md:py-6 transform hover:scale-105 transition-all duration-300 shadow-lg hover:shadow-xl"
|
||||
>
|
||||
Get Started
|
||||
</Link>
|
||||
<Link
|
||||
to="/login"
|
||||
className="bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-full px-6 py-4 md:px-8 md:py-6 transform hover:scale-105 transition-all duration-300 shadow-lg hover:shadow-xl"
|
||||
>
|
||||
Login
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
{/* Right Side - Image */}
|
||||
<div className="w-full md:w-1/2 flex justify-center order-2 md:order-1">
|
||||
<div className="relative p-4 bg-gradient-to-r from-blue-50 to-emerald-50 rounded-2xl max-w-xs sm:max-w-lg md:max-w-md lg:max-w-lvh">
|
||||
<img
|
||||
src="/Dashboard.png"
|
||||
alt="Drive-thru Dashboard Interface"
|
||||
className="w-full rounded-xl shadow-2xl transition-shadow duration-300"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-r from-blue-500/5 to-emerald-500/5 rounded-2xl pointer-events-none"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Features Section */}
|
||||
<div
|
||||
id="features"
|
||||
className="w-full max-w-5xl mx-auto p-6 sm:p-8 bg-gray-100 rounded-lg shadow-lg"
|
||||
>
|
||||
<h2 className="text-3xl font-bold text-center mb-8">Key Features</h2>
|
||||
<div className="flex flex-col-reverse md:flex-row items-center gap-8 lg:gap-12">
|
||||
{/* Left Side - Image */}
|
||||
<div className="w-full md:w-1/2 flex justify-center">
|
||||
<img
|
||||
src="/He.png"
|
||||
alt="Feature Illustration"
|
||||
className="w-full max-w-xs sm:max-w-sm md:max-w-md lg:max-w-lg object-contain rounded-lg shadow-md"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Right Side - Feature List */}
|
||||
<div className="w-full md:w-1/2">
|
||||
<div className="space-y-6">
|
||||
{features.map((feature, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`p-5 border-2 rounded-lg cursor-pointer transition-all duration-500 ${
|
||||
index === activeIndex
|
||||
? "border-blue-500 bg-white shadow-lg scale-105"
|
||||
: "border-gray-300"
|
||||
}`}
|
||||
onClick={() => handleFeatureClick(index)}
|
||||
>
|
||||
<div className="flex items-center space-x-4">
|
||||
{feature.icon}
|
||||
<h3 className="text-lg font-semibold">{feature.title}</h3>
|
||||
</div>
|
||||
{index === activeIndex && (
|
||||
<p className="text-gray-600 mt-3 transition-opacity duration-500 opacity-100">
|
||||
{feature.description}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* How It Works Section */}
|
||||
<div
|
||||
id="howItWorks"
|
||||
className="w-full max-w-5xl mx-auto p-6 sm:p-8 bg-gray-100 rounded-lg shadow-lg"
|
||||
>
|
||||
<h2 className="text-3xl font-bold text-center mb-8">How It Works</h2>
|
||||
<div className="flex flex-col md:flex-row items-center gap-8 lg:gap-12">
|
||||
{/* Left Side - Feature List */}
|
||||
<div className="w-full md:w-1/2">
|
||||
<div className="space-y-6">
|
||||
{howItWorks.map((howItWork, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`p-5 border-2 rounded-lg cursor-pointer transition-all duration-500 ${
|
||||
index === activeIndex1
|
||||
? "border-blue-500 bg-white shadow-lg scale-105"
|
||||
: "border-gray-300"
|
||||
}`}
|
||||
onClick={() => handleFeatureClick1(index)}
|
||||
>
|
||||
<div className="flex items-center space-x-4">
|
||||
{howItWork.icon}
|
||||
<h3 className="text-lg font-semibold">{howItWork.title}</h3>
|
||||
</div>
|
||||
{index === activeIndex1 && (
|
||||
<p className="text-gray-600 mt-3 transition-opacity duration-500 opacity-100">
|
||||
{howItWork.description}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Side - Image */}
|
||||
<div className="w-full md:w-1/2 flex justify-center">
|
||||
<img
|
||||
src="/She.png"
|
||||
alt="Feature Illustration"
|
||||
className="w-full max-w-xs sm:max-w-sm md:max-w-md lg:max-w-lg object-contain rounded-lg shadow-md"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DrivethruLandingPage;
|
||||
@@ -1,32 +0,0 @@
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
const NotFoundPage = () => {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center h-screen bg-gray-100 p-4">
|
||||
{/* Placeholder SVG - Replace this with your SVG */}
|
||||
<img
|
||||
src="/404.png"
|
||||
style={{ width: "30%", height: "auto" }}
|
||||
alt="404 Not Found"
|
||||
></img>
|
||||
{/* Page number and title */}
|
||||
<h2 className="text-2xl font-bold mb-4 mt-4">Page Not Found</h2>
|
||||
|
||||
{/* Description text */}
|
||||
<p className="text-center text-gray-700 mb-6">
|
||||
Sorry, we couldn't find the page you were looking for. It may have
|
||||
been moved or deleted.
|
||||
</p>
|
||||
|
||||
{/* Call-to-action button */}
|
||||
<Link
|
||||
to="/"
|
||||
className="px-6 py-2 bg-[#1877F2] text-white rounded hover:bg-blue-600 transition duration-200"
|
||||
>
|
||||
Go Home
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default NotFoundPage;
|
||||
@@ -1,34 +0,0 @@
|
||||
// utils/api.js
|
||||
export const uploadFileToHDFS = async (
|
||||
file,
|
||||
hdfsPath,
|
||||
uploadedFileName,
|
||||
username
|
||||
) => {
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
formData.append("hdfsPath", "/kalas");
|
||||
formData.append("uploadedFileName", uploadedFileName);
|
||||
formData.append("username", "kalas");
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
"http://192.168.29.61:8080/api/hdfs/uploadFile",
|
||||
{
|
||||
method: "POST",
|
||||
body: formData,
|
||||
}
|
||||
);
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json(); // or response.json() if JSON is returned
|
||||
|
||||
console.log("Response:", data);
|
||||
} else {
|
||||
console.error("Upload failed with status:", response.status);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error uploading file:", error);
|
||||
alert("An error occurred while uploading the file.");
|
||||
}
|
||||
};
|
||||
@@ -1,16 +0,0 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import tailwindcss from '@tailwindcss/vite'
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
react(),
|
||||
tailwindcss(),
|
||||
],
|
||||
server: {
|
||||
host: 'localhost',
|
||||
port: 5173,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,26 +1,6 @@
|
||||
# CC-MINI (2025)
|
||||
|
||||
---
|
||||
|
||||
## Git config
|
||||
|
||||
Create a new directory for this project, and run these following commands for initalizing git:
|
||||
|
||||
```shell
|
||||
git clone https://github.com/kshitij-ka/cc-mini.git
|
||||
cd cc-mini
|
||||
git config --local user.name "Your name"
|
||||
git config --local user.email "your@ema.il"
|
||||
git config --local core.autocrlf input # For Linux/MacOS users
|
||||
git config --local core.autocrlf true # For Windows users
|
||||
git checkout frontend # If you're working on frontend
|
||||
git checkout backend # If you're working on backend
|
||||
```
|
||||
|
||||
## Where to push?
|
||||
|
||||
- For frontend, please push to [Frontend](https://github.com/kshitij-ka/cc-mini/tree/frontend/Frontend) folder in the [frontend branch](https://github.com/kshitij-ka/cc-mini/tree/frontend).
|
||||
- For backend, please push to [Backend](https://github.com/kshitij-ka/cc-mini/tree/backend/Backend) folder in the [backend branch](https://github.com/kshitij-ka/cc-mini/tree/backend/).
|
||||
- I will be merging changes from both the branches in the main branch for deploying.
|
||||
`backend` branch is intended only for pushing backend files within the [Backend](Backend/) folder.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"name": "cc-mini",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {}
|
||||
}
|
||||