Skip to content

Commit f26e24b

Browse files
tegiozcynthia-sg
andauthored
Make job board embeddable (#227)
Signed-off-by: Sergio Castaño Arteaga <[email protected]> Signed-off-by: Cintia Sánchez García <[email protected]> Co-authored-by: Cintia Sánchez García <[email protected]>
1 parent b64f7b2 commit f26e24b

File tree

30 files changed

+460
-230
lines changed

30 files changed

+460
-230
lines changed

gitjobs-server/src/auth.rs

-2
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,6 @@ pub(crate) struct PasswordCredentials {
369369

370370
/// User information.
371371
#[derive(Clone, Serialize, Deserialize)]
372-
#[allow(clippy::struct_field_names, dead_code)]
373372
pub(crate) struct User {
374373
pub user_id: Uuid,
375374
pub auth_hash: Vec<u8>,
@@ -407,7 +406,6 @@ impl std::fmt::Debug for User {
407406
/// User information summary.
408407
#[skip_serializing_none]
409408
#[derive(Clone, Serialize, Deserialize)]
410-
#[allow(clippy::struct_field_names)]
411409
pub(crate) struct UserSummary {
412410
pub email: String,
413411
pub name: String,

gitjobs-server/src/db/dashboard/employer.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ use uuid::Uuid;
99

1010
use crate::{
1111
PgDB,
12-
db::misc::Total,
1312
templates::{
1413
dashboard::employer::{
1514
applications::{self, Application},
@@ -808,5 +807,5 @@ impl DBDashBoardEmployer for PgDB {
808807
#[derive(Debug, Clone, Serialize, Deserialize)]
809808
pub(crate) struct ApplicationsSearchOutput {
810809
pub applications: Vec<Application>,
811-
pub total: Total,
810+
pub total: usize,
812811
}

gitjobs-server/src/db/jobboard.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use uuid::Uuid;
1111

1212
use crate::{
1313
PgDB,
14-
db::misc::Total,
1514
templates::jobboard::jobs::{Filters, FiltersOptions, Job, JobSummary},
1615
};
1716

@@ -262,5 +261,5 @@ impl DBJobBoard for PgDB {
262261
#[derive(Debug, Clone, Serialize, Deserialize)]
263262
pub(crate) struct JobsSearchOutput {
264263
pub jobs: Vec<JobSummary>,
265-
pub total: Total,
264+
pub total: usize,
266265
}

gitjobs-server/src/db/misc.rs

-3
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,3 @@ impl DBMisc for PgDB {
122122
Ok(projects)
123123
}
124124
}
125-
126-
/// Type alias to represent the total count.
127-
pub(crate) type Total = usize;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//! This module defines the HTTP handlers for the embed page.
2+
3+
use anyhow::Result;
4+
use askama::Template;
5+
use axum::{
6+
extract::State,
7+
response::{Html, IntoResponse},
8+
};
9+
use chrono::Duration;
10+
use serde_qs::axum::QsQuery;
11+
use tracing::instrument;
12+
13+
use crate::{
14+
config::HttpServerConfig,
15+
db::{DynDB, jobboard::JobsSearchOutput},
16+
handlers::{error::HandlerError, prepare_headers},
17+
templates::jobboard::{embed::Page, jobs::Filters},
18+
};
19+
20+
/// Handler that returns the embed page.
21+
#[instrument(skip_all, err)]
22+
pub(crate) async fn page(
23+
State(cfg): State<HttpServerConfig>,
24+
State(db): State<DynDB>,
25+
QsQuery(filters): QsQuery<Filters>,
26+
) -> Result<impl IntoResponse, HandlerError> {
27+
// Get jobs that match the query
28+
let JobsSearchOutput { jobs, total: _ } = db.search_jobs(&filters).await?;
29+
30+
// Prepare template
31+
let template = Page {
32+
base_url: cfg.base_url.strip_suffix('/').unwrap_or(&cfg.base_url).to_string(),
33+
jobs,
34+
};
35+
36+
// Prepare response headers
37+
let headers = prepare_headers(Duration::minutes(10), &[])?;
38+
39+
Ok((headers, Html(template.render()?)))
40+
}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! This module defines the HTTP handlers for the job board.
22
33
pub(crate) mod about;
4+
pub(crate) mod embed;
45
pub(crate) mod home;
56
pub(crate) mod jobs;

gitjobs-server/src/main.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![warn(clippy::all, clippy::pedantic)]
2+
#![allow(clippy::struct_field_names)]
23

34
use std::{path::PathBuf, sync::Arc};
45

gitjobs-server/src/notifications.rs

-1
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,6 @@ pub(crate) struct NewNotification {
239239

240240
/// Information required to deliver a notification.
241241
#[derive(Debug, Clone)]
242-
#[allow(clippy::struct_field_names)]
243242
pub(crate) struct Notification {
244243
pub notification_id: Uuid,
245244
pub email: String,

gitjobs-server/src/router.rs

+1
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ pub(crate) async fn setup(
100100
))
101101
.route("/", get(jobboard::jobs::jobs_page))
102102
.route("/about", get(jobboard::about::page))
103+
.route("/embed", get(jobboard::embed::page))
103104
.route("/health-check", get(health_check))
104105
.nest("/jobboard/images", jobboard_images_router)
105106
.route("/locations/search", get(search_locations))

gitjobs-server/src/templates/dashboard/employer/applications.rs

-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ impl ApplicationsPage {
4040

4141
/// Application information.
4242
#[derive(Debug, Clone, Serialize, Deserialize)]
43-
#[allow(clippy::struct_field_names)]
4443
pub(crate) struct Application {
4544
application_id: Uuid,
4645
name: String,

gitjobs-server/src/templates/dashboard/employer/home.rs

-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ use crate::templates::{
1919
/// Home page template.
2020
#[derive(Debug, Clone, Template)]
2121
#[template(path = "dashboard/employer/home.html")]
22-
#[allow(clippy::struct_field_names)]
2322
pub(crate) struct Page {
2423
pub content: Content,
2524
pub employers: Vec<employer::employers::EmployerSummary>,

gitjobs-server/src/templates/dashboard/employer/jobs.rs

-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ pub(crate) struct JobSummary {
6565
/// Job details.
6666
#[skip_serializing_none]
6767
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
68-
#[allow(clippy::struct_field_names)]
6968
pub(crate) struct Job {
7069
pub description: String,
7170
pub status: JobStatus,

gitjobs-server/src/templates/dashboard/job_seeker/applications.rs

-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ pub(crate) struct ApplicationsPage {
2020

2121
/// Application information.
2222
#[derive(Debug, Clone, Serialize, Deserialize)]
23-
#[allow(clippy::struct_field_names)]
2423
pub(crate) struct Application {
2524
pub application_id: Uuid,
2625
pub applied_at: DateTime<Utc>,

gitjobs-server/src/templates/dashboard/job_seeker/home.rs

-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use crate::templates::{
1717
/// Home page template.
1818
#[derive(Debug, Clone, Template)]
1919
#[template(path = "dashboard/job_seeker/home.html")]
20-
#[allow(clippy::struct_field_names)]
2120
pub(crate) struct Page {
2221
pub content: Content,
2322
pub page_id: PageId,

gitjobs-server/src/templates/helpers.rs

-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ pub(crate) fn format_location(
6666

6767
/// Check if the value provided is none or some and default.
6868
#[allow(clippy::ref_option)]
69-
#[allow(dead_code)]
7069
pub(crate) fn option_is_none_or_default<T: Default + PartialEq>(v: &Option<T>) -> bool {
7170
if let Some(value) = v {
7271
return *value == T::default();

gitjobs-server/src/templates/jobboard/about.rs

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use crate::templates::{PageId, auth::User, filters};
1010
/// About page template.
1111
#[derive(Debug, Clone, Template, Serialize, Deserialize)]
1212
#[template(path = "jobboard/about/page.html")]
13-
#[allow(clippy::struct_field_names)]
1413
pub(crate) struct Page {
1514
pub content: String,
1615
pub page_id: PageId,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//! This module defines some templates and types used in the embed page.
2+
3+
use askama::Template;
4+
use serde::{Deserialize, Serialize};
5+
6+
use crate::templates::{
7+
dashboard::employer::jobs::{JobKind, Workplace},
8+
filters,
9+
helpers::{DATE_FORMAT_3, build_jobboard_image_url},
10+
jobboard::jobs::JobSummary,
11+
};
12+
13+
/// Embed page template.
14+
#[derive(Debug, Clone, Template, Serialize, Deserialize)]
15+
#[template(path = "jobboard/embed/page.html")]
16+
pub(crate) struct Page {
17+
pub base_url: String,
18+
pub jobs: Vec<JobSummary>,
19+
}

gitjobs-server/src/templates/jobboard/home.rs

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use crate::templates::{PageId, auth::User, filters};
1010
/// Home page template.
1111
#[derive(Debug, Clone, Template, Serialize, Deserialize)]
1212
#[template(path = "jobboard/home.html")]
13-
#[allow(clippy::struct_field_names)]
1413
pub(crate) struct Page {
1514
pub page_id: PageId,
1615
pub user: User,

gitjobs-server/src/templates/jobboard/jobs.rs

-2
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,6 @@ pub(crate) struct JobSummary {
182182
/// Employer details.
183183
#[skip_serializing_none]
184184
#[derive(Debug, Clone, Serialize, Deserialize)]
185-
#[allow(clippy::struct_field_names)]
186185
pub(crate) struct Employer {
187186
pub company: String,
188187
pub employer_id: Uuid,
@@ -196,7 +195,6 @@ pub(crate) struct Employer {
196195
/// Job details.
197196
#[skip_serializing_none]
198197
#[derive(Debug, Clone, Serialize, Deserialize)]
199-
#[allow(clippy::struct_field_names)]
200198
pub(crate) struct Job {
201199
pub description: String,
202200
pub employer: Employer,
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! This module defines the templates for the job board pages.
22
33
pub(crate) mod about;
4+
pub(crate) mod embed;
45
pub(crate) mod home;
56
pub(crate) mod jobs;

gitjobs-server/src/templates/misc.rs

-4
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,13 @@ pub(crate) struct UserMenuSection {
4141

4242
/// Foundation information.
4343
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
44-
#[allow(clippy::struct_field_names)]
4544
pub(crate) struct Foundation {
4645
pub foundation_id: Uuid,
4746
pub name: String,
4847
}
4948

5049
/// Location information.
5150
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
52-
#[allow(clippy::struct_field_names)]
5351
pub(crate) struct Location {
5452
pub location_id: Uuid,
5553
pub city: String,
@@ -71,7 +69,6 @@ impl std::fmt::Display for Location {
7169

7270
/// Member information.
7371
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
74-
#[allow(clippy::struct_field_names)]
7572
pub(crate) struct Member {
7673
pub member_id: Uuid,
7774
pub foundation: String,
@@ -82,7 +79,6 @@ pub(crate) struct Member {
8279

8380
/// Project information.
8481
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
85-
#[allow(clippy::struct_field_names)]
8682
pub(crate) struct Project {
8783
pub project_id: Uuid,
8884
pub foundation: String,

gitjobs-server/static/css/styles.src.css

+5
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,11 @@ select.aligned-right option {
364364
-webkit-mask-image: url("/static/images/icons/company.svg");
365365
}
366366

367+
.icon-copy {
368+
mask-image: url("/static/images/icons/copy.svg");
369+
-webkit-mask-image: url("/static/images/icons/copy.svg");
370+
}
371+
367372
.icon-draft {
368373
mask-image: url("/static/images/icons/draft.svg");
369374
-webkit-mask-image: url("/static/images/icons/draft.svg");
Loading

gitjobs-server/static/js/jobboard/job_section.js

+23
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,26 @@ export const applyButton = () => {
5757
}
5858
}
5959
};
60+
61+
export const renderEmbedCode = () => {
62+
const embedCode = document.getElementById("embed-code");
63+
const params = new URLSearchParams(window.location.search);
64+
params.append("limit", "10");
65+
embedCode.textContent = `
66+
<iframe id="gitjobs" src="${window.location.origin}/embed?${params.toString()}" style="width:100%;max-width:870px;height:100%;display:block;border:none;"></iframe>
67+
68+
<!-- Uncomment the following lines for resizing iframes dynamically using open-iframe-resizer
69+
<script type="module">
70+
import { initialize } from "https://cdn.jsdelivr.net/npm/@open-iframe-resizer/core@latest/dist/index.js";
71+
initialize({}, "#gitjobs");
72+
</script> -->`;
73+
};
74+
75+
export const copyEmbedCodeToClipboard = (elId) => {
76+
const embedCode = document.getElementById(elId);
77+
78+
// Copy the text inside the text field
79+
navigator.clipboard.writeText(embedCode.textContent);
80+
81+
showSuccessAlert("Embed code copied to clipboard!");
82+
};

gitjobs-server/static/vendor/js/open-iframe-resizer.v1.3.1.min.js

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gitjobs-server/templates/dashboard/job_seeker/profile/preview.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@
108108
{% call title(content = "Skills") -%}
109109
<div class="text-stone-600 text-xs/6 flex flex-wrap pt-2">
110110
{% for skill in skills -%}
111-
<div class="bg-stone-100 px-4 rounded-full inline-block capitalize mb-2 me-2">{{ skill|unnormalize }}</div>
111+
<div class="bg-stone-100 px-4 rounded-full inline-block uppercase mb-2 me-2">{{ skill|unnormalize }}</div>
112112
{% endfor -%}
113113
</div>
114114
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
{% import "jobboard/jobs/results_section.html" as macros -%}
2+
<!DOCTYPE html>
3+
{# djlint:off H030 H031 #}
4+
<html lang="en">
5+
<head>
6+
<title>GitJobs</title>
7+
<link rel="stylesheet" href="{{ base_url }}/static/css/styles.css" />
8+
</head>
9+
<body class="font-inter">
10+
<div class="relative flex flex-col bg-white border border-stone-200 rounded-lg py-5 md:py-7">
11+
{# GitJobs logo -#}
12+
<div class="px-5 md:px-7">
13+
<a href="{{ base_url }}"
14+
target="_blank"
15+
rel="noopener noreferrer"
16+
class="inline-flex items-top gap-x-2">
17+
<div class="h-[28px] w-[138px] md:h-[33px] md:w-[162px] ms-[2px]">
18+
<img src="{{ base_url }}/static/images/gitjobs.png"
19+
height="auto"
20+
width="auto"
21+
class="h-full w-full"
22+
alt="GitJobs Logo">
23+
</div>
24+
<div>
25+
<div class="relative text-[0.7rem]/5 md:text-xs/6 tracking-widest rounded-full bg-stone-400/20 px-2 font-semibold">
26+
BETA
27+
</div>
28+
</div>
29+
</a>
30+
</div>
31+
{# End GitJobs logo -#}
32+
33+
<div class="flex flex-col mt-5 md:mt-7 space-y-4">
34+
{# When jobs is empty -#}
35+
{% if jobs.len() == 0 -%}
36+
<div class="border border-stone-300 p-5 lg:p-10 text-sm text-stone-800 rounded-lg bg-stone-50/50 text-center mx-5 md:mx-7"
37+
role="alert">
38+
<div class="text-md lg:text-lg py-6 md:py-12">
39+
At the moment there are no jobs that match your filtering criteria.
40+
</div>
41+
</div>
42+
{% else -%}
43+
{% for job in jobs -%}
44+
{% let open_source = job.open_source.unwrap_or_default() -%}
45+
{% let upstream_commitment = job.upstream_commitment.unwrap_or_default() -%}
46+
47+
<a href="{{ base_url }}/?job_id={{ job.job_id }}"
48+
target="_blank"
49+
rel="noopener noreferrer"
50+
class="relative mx-4 md:mx-7 text-start enabled:cursor-pointer border-2 rounded-lg enabled:hover:outline enabled:hover:outline-1 p-5 md:p-7 {%- if upstream_commitment > 0 %} border-lime-500 bg-lime-50/20 enabled:hover:outline-lime-500{%- else if open_source > 0 %} border-lime-300 bg-lime-50/20 enabled:hover:outline-lime-300{%- else %} border-stone-200 enabled:hover:outline-stone-200{%- endif -%}">{% call macros::job_card(job = job) -%}</a>
51+
{% endfor -%}
52+
{% endif -%}
53+
</div>
54+
</div>
55+
<script type="module"
56+
src="{{base_url}}/static/vendor/js/open-iframe-resizer.v1.3.1.min.js"></script>
57+
</body>
58+
</html>
59+
{# djlint:on #}

0 commit comments

Comments
 (0)