Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 43 additions & 17 deletions pkg/data/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ type Job struct {
Description sql.NullString `db:"description" json:"-"`
DescriptionJSON *string `db:"-" json:"description"`
Email string `db:"email" json:"email"`
PublishedAt time.Time `db:"published_at" json:"published_at"`
Published bool `db:"published" json:"published"`
PublishedAt sql.NullTime `db:"published_at" json:"published_at"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
}

const (
Expand All @@ -47,6 +49,10 @@ func (job *Job) Update(newParams NewJob) {

job.Description.String = newParams.Description
job.Description.Valid = newParams.Description != ""

// Mark job posting as valid and publish
job.Published = true
job.PublishedAt.Time = time.Now()
}

func (job *Job) RenderDescription() (string, error) {
Expand Down Expand Up @@ -75,8 +81,8 @@ func (job *Job) RenderDescription() (string, error) {

func (job *Job) Save(db *sqlx.DB) (sql.Result, error) {
return db.Exec(
"UPDATE jobs SET position = $1, organization = $2, url = $3, description = $4 WHERE id = $5",
job.Position, job.Organization, job.Url, job.Description, job.ID,
"UPDATE jobs SET position = $1, organization = $2, url = $3, description = $4, published = $5, published_at = $6 WHERE id = $7",
job.Position, job.Organization, job.Url, job.Description, job.Published, job.PublishedAt, job.ID,
)
}

Expand All @@ -85,7 +91,7 @@ func (job *Job) AuthSignature(secret string) string {
"%s:%s:%s",
job.ID,
job.Email,
job.PublishedAt.String(),
job.CreatedAt.String(),
)

hash := hmac.New(sha256.New, []byte(secret))
Expand Down Expand Up @@ -114,6 +120,26 @@ func GetAllJobs(db *sqlx.DB) ([]Job, error) {
return jobs, nil
}

func GetAllPublishedJobs(db *sqlx.DB) ([]Job, error) {
var jobs []Job

err := db.Select(&jobs, "SELECT * FROM jobs WHERE published = true ORDER BY published_at DESC")
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return jobs, err
}

for i := range jobs {
if !jobs[i].Url.Valid {
jobs[i].JSONUrl = &jobs[i].Url.String
}
if !jobs[i].Description.Valid {
jobs[i].DescriptionJSON = &jobs[i].Description.String
}
}

return jobs, nil
}

func GetJob(id string, db *sqlx.DB) (Job, error) {
var job Job

Expand All @@ -132,19 +158,19 @@ func GetJob(id string, db *sqlx.DB) (Job, error) {
return job, nil
}

func DeleteJob(id string, db *sqlx.DB) (error) {
result, err := db.Exec("DELETE FROM jobs WHERE id = $1", id)
if err != nil {
return err
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return err
}
if rowsAffected != 1 {
return fmt.Errorf("failed to delete job: %w", err)
}
return nil
func DeleteJob(id string, db *sqlx.DB) error {
result, err := db.Exec("DELETE FROM jobs WHERE id = $1", id)
if err != nil {
return err
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return err
}
if rowsAffected != 1 {
return fmt.Errorf("failed to delete job: %w", err)
}
return nil
}

type NewJob struct {
Expand Down
12 changes: 6 additions & 6 deletions pkg/server/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type Controller struct {
}

func (ctrl *Controller) Index(ctx *gin.Context) {
jobs, err := data.GetAllJobs(ctrl.DB)
jobs, err := data.GetAllPublishedJobs(ctrl.DB)
if err != nil {
log.Println(fmt.Errorf("Index failed to getAllJobs: %w", err))
ctx.AbortWithStatus(http.StatusInternalServerError)
Expand Down Expand Up @@ -123,7 +123,7 @@ func (ctrl *Controller) CreateJob(ctx *gin.Context) {

if ctrl.EmailService != nil {
// TODO: make this a nicer html template?
subject := fmt.Sprintf("Job %s Created!", newJobInput.Position)
subject := fmt.Sprintf("Job %s Created(draft)!", newJobInput.Position)
message := fmt.Sprintf(`
<!doctype html>
<html>
Expand All @@ -144,9 +144,10 @@ func (ctrl *Controller) CreateJob(ctx *gin.Context) {
<body>
<div class="container">
<h1>Job %s Created!</h1>
<p>Congratulations! Your job posting for the position <strong>%s</strong> has been successfully created.</p>
<p>You can edit or update your job posting by clicking the link below:</p>
<p>Congratulations! Your draft job posting for the position <strong>%s</strong> has been successfully created.</p>
<p>You can edit your job posting and publish it by clicking the link below:</p>
<p><a href="%s">Edit Job Posting</a></p>
<p><i>Note: Your job posting will not be live until you click <b>Publish.</b></i></p>
<div class="footer">
<p>&copy; <a href="https://jobs.devict.org/">Job Board</a></p>
</div>
Expand Down Expand Up @@ -176,7 +177,7 @@ func (ctrl *Controller) CreateJob(ctx *gin.Context) {
}
}

session.AddFlash("Job created!")
session.AddFlash("Job created in draft status! Check email to publish.")
ctx.Redirect(302, "/")
}

Expand Down Expand Up @@ -276,7 +277,6 @@ func (ctrl *Controller) DeleteJob(ctx *gin.Context) {
ctx.Redirect(http.StatusFound, "/")
}


func addFlash(ctx *gin.Context, base gin.H) gin.H {
session := sessions.Default(ctx)
base["flashes"] = session.Flashes()
Expand Down
4 changes: 4 additions & 0 deletions sql/20260201141821_update_jobs.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ALTER TABLE jobs
DROP COLUMN IF EXISTS published,
DROP COLUMN IF EXISTS published_at;
ALTER TABLE jobs RENAME created_at TO published_at;
4 changes: 4 additions & 0 deletions sql/20260201141821_update_jobs.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ALTER TABLE jobs RENAME published_at TO created_at;
ALTER TABLE jobs
ADD COLUMN IF NOT EXISTS published BOOLEAN DEFAULT false,
ADD COLUMN IF NOT EXISTS published_at TIMESTAMP DEFAULT null;
2 changes: 1 addition & 1 deletion templates/edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
<textarea name="description" rows="4" class="form-textarea mb-3">{{ .job.Description.String }}</textarea>
</label>
<div class="flex gap-4 mt-6">
<button class="btn btn-primary">Update</button>
<button class="btn btn-primary">Publish</button>
</div>
</form>

Expand Down
8 changes: 5 additions & 3 deletions templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ <h2 class="m-0 font-bold text-lg">{{ .Position }}</h2>
href="/jobs/{{ .ID }}"
class="relative z-10 text-gray-500 hover:underline focus:underline"
>
<time datetime="{{ .PublishedAt | formatAsRfc3339String }}" class="text-sm">
Posted {{ .PublishedAt | formatAsDate }}
</time>
{{ if .PublishedAt.Valid }}
<time datetime="{{ .PublishedAt.Time | formatAsRfc3339String }}" class="text-sm">
Posted {{ .PublishedAt.Time | formatAsDate }}
</time>
{{end}}
</a>
</div>
{{ if .Url.Valid }}
Expand Down
Loading