Skip to content

Commit

Permalink
Merge pull request #40 from SinTan1729/get-longlink
Browse files Browse the repository at this point in the history
Get longlink
  • Loading branch information
SinTan1729 authored Jan 8, 2025
2 parents f952cb8 + 1be89db commit a5621ac
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 35 deletions.
56 changes: 31 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,31 +162,6 @@ below, replace `http://localhost:4567` with where your instance of `chhoto-url`
You can get the version of `chhoto-url` the server is running using `curl http://localhost:4567/api/version` and
get the siteurl using `curl http://localhost:4567/api/siteurl`. These routes are accessible without any authentication.

### Cookie validation
If you have set up a password, first do the following to get an authentication cookie and store it in a file.
```bash
curl -X POST -d "<your-password>" -c cookie.txt http://localhost:4567/api/login
```
You should receive "Correct password!" if the provided password was correct. For any subsequent
request, please add `-b cookie.txt` to provide authentication.

To add a link, do
```bash
curl -X POST -d '{"shortlink":"<shortlink>", "longlink":"<longlink>"}' http://localhost:4567/api/new
```
Send an empty `<shortlink>` if you want it to be auto-generated. The server will reply with the generated shortlink.

To get a list of all the currently available links as `json`, do
```bash
curl http://localhost:4567/api/all
```

To delete a link, do
```bash
curl -X DELETE http://localhost:4567/api/del/<shortlink>
```
The server will send a confirmation.

### API key validation
**This is required for programs that rely on a JSON response from Chhoto URL**

Expand All @@ -201,6 +176,12 @@ curl -X POST -H "X-API-Key: <YOUR_API_KEY>" -d '{"shortlink":"<shortlink>", "lon
```
Send an empty `<shortlink>` if you want it to be auto-generated. The server will reply with the generated shortlink.

To get information about a single shortlink:
``` bash
curl -H "X-API-Key: <YOUR_API_KEY>" -d '<shortlink>' http://localhost:4567/api/expand
```
(This route is not accessible using cookie validation.)

To get a list of all the currently available links:
``` bash
curl -H "X-API-Key: <YOUR_API_KEY>" http://localhost:4567/api/all
Expand All @@ -215,6 +196,31 @@ Where `<shortlink>` is name of the shortened link you would like to delete. For

The server will output when the instance is accessed over API, when an incorrect API key is received, etc.

### Cookie validation
If you have set up a password, first do the following to get an authentication cookie and store it in a file.
```bash
curl -X POST -d "<your-password>" -c cookie.txt http://localhost:4567/api/login
```
You should receive "Correct password!" if the provided password was correct. For any subsequent
request, please add `-b cookie.txt` to provide authentication.

To add a link, do
```bash
curl -X POST -d '{"shortlink":"<shortlink>", "longlink":"<longlink>"}' http://localhost:4567/api/new
```
Send an empty `<shortlink>` if you want it to be auto-generated. The server will reply with the generated shortlink.

To get a list of all the currently available links as `json`, do
```bash
curl http://localhost:4567/api/all
```

To delete a link, do
```bash
curl -X DELETE http://localhost:4567/api/del/<shortlink>
```
The server will send a confirmation.

## Disable authentication
If you do not define a password environment variable when starting the docker image, authentication
will be disabled.
Expand Down
15 changes: 11 additions & 4 deletions actix/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,21 @@ pub struct DBRow {
}

// Find a single URL
pub fn find_url(shortlink: &str, db: &Connection) -> Option<String> {
pub fn find_url(shortlink: &str, db: &Connection, needhits: bool) -> (Option<String>, Option<i64>) {
let query = if needhits {
"SELECT long_url,hits FROM urls WHERE short_url = ?1"
} else {
"SELECT long_url FROM urls WHERE short_url = ?1"
};
let mut statement = db
.prepare_cached("SELECT long_url FROM urls WHERE short_url = ?1")
.prepare_cached(query)
.expect("Error preparing SQL statement for find_url.");

statement
let longlink = statement
.query_row([shortlink], |row| row.get("long_url"))
.ok()
.ok();
let hits = statement.query_row([shortlink], |row| row.get("hits")).ok();
(longlink, hits)
}

// Get all URLs in DB
Expand Down
1 change: 1 addition & 0 deletions actix/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ async fn main() -> Result<()> {
.service(services::delete_link)
.service(services::login)
.service(services::logout)
.service(services::expand)
.service(Files::new("/", "./resources/").index_file("index.html"))
.default_service(actix_web::web::get().to(services::error404))
})
Expand Down
42 changes: 40 additions & 2 deletions actix/src/services.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,23 @@ struct Response {
reason: String,
}

// Needs to return the short URL to make it easier for programs leveraging the API
// Needed to return the short URL to make it easier for programs leveraging the API
#[derive(Serialize)]
struct CreatedURL {
success: bool,
error: bool,
shorturl: String,
}

// Struct for returning information about a shortlink
#[derive(Serialize)]
struct LinkInfo {
success: bool,
error: bool,
longurl: String,
hits: i64,
}

// Define the routes

// Add new links
Expand Down Expand Up @@ -123,6 +132,35 @@ pub async fn getall(
}
}

// Get information about a single shortlink
#[post("/api/expand")]
pub async fn expand(req: String, data: web::Data<AppState>, http: HttpRequest) -> HttpResponse {
let result = utils::is_api_ok(http);
if result.success {
let linkinfo = utils::get_longurl(req, &data.db, true);
if let Some(longlink) = linkinfo.0 {
let body = LinkInfo {
success: true,
error: false,
longurl: longlink,
hits: linkinfo
.1
.expect("Error getting hit count for existing shortlink."),
};
HttpResponse::Ok().json(body)
} else {
let body = Response {
success: false,
error: true,
reason: "The shortlink does not exist on the server.".to_string(),
};
HttpResponse::Unauthorized().json(body)
}
} else {
HttpResponse::Unauthorized().json(result)
}
}

// Get the site URL
#[get("/api/siteurl")]
pub async fn siteurl() -> HttpResponse {
Expand Down Expand Up @@ -154,7 +192,7 @@ pub async fn link_handler(
data: web::Data<AppState>,
) -> impl Responder {
let shortlink_str = shortlink.to_string();
if let Some(longlink) = utils::get_longurl(shortlink_str, &data.db) {
if let Some(longlink) = utils::get_longurl(shortlink_str, &data.db, false).0 {
let redirect_method = env::var("redirect_method").unwrap_or(String::from("PERMANENT"));
database::add_hit(shortlink.as_str(), &data.db);
if redirect_method == "TEMPORARY" {
Expand Down
8 changes: 4 additions & 4 deletions actix/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@ pub fn is_api_ok(http: HttpRequest) -> Response {
}

// Request the DB for searching an URL
pub fn get_longurl(shortlink: String, db: &Connection) -> Option<String> {
pub fn get_longurl(shortlink: String, db: &Connection, needhits: bool) -> (Option<String>, Option<i64>) {
if validate_link(&shortlink) {
database::find_url(shortlink.as_str(), db)
database::find_url(shortlink.as_str(), db, needhits)
} else {
None
(None, None)
}
}

Expand Down Expand Up @@ -124,7 +124,7 @@ pub fn add_link(req: String, db: &Connection) -> (bool, String) {
}

if validate_link(chunks.shortlink.as_str())
&& get_longurl(chunks.shortlink.clone(), db).is_none()
&& get_longurl(chunks.shortlink.clone(), db, false).0.is_none()
{
(
database::add_link(chunks.shortlink.clone(), chunks.longlink, db),
Expand Down

0 comments on commit a5621ac

Please sign in to comment.