Merge pull request #282 from pateljannat/job-posting

This commit is contained in:
Jannat Patel
2021-12-30 14:54:08 +05:30
committed by GitHub
31 changed files with 612 additions and 25 deletions

View File

@@ -701,6 +701,60 @@
"unique": 0,
"width": null
},
{
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"collapsible_depends_on": null,
"columns": 0,
"default": null,
"depends_on": null,
"description": null,
"docstatus": 0,
"doctype": "Custom Field",
"dt": "User",
"fetch_from": null,
"fetch_if_empty": 0,
"fieldname": "looking_for_job",
"fieldtype": "Check",
"hidden": 0,
"hide_border": 0,
"hide_days": 0,
"hide_seconds": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_preview": 0,
"in_standard_filter": 0,
"insert_after": "cover_image",
"label": "I am looking for a job",
"length": 0,
"mandatory_depends_on": null,
"modified": "2021-12-28 12:56:32.110403",
"module": null,
"name": "User-looking_for_job",
"no_copy": 0,
"non_negative": 0,
"options": null,
"parent": null,
"parentfield": null,
"parenttype": null,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": null,
"read_only": 0,
"read_only_depends_on": null,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"translatable": 0,
"unique": 0,
"width": null
},
{
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
@@ -1889,4 +1943,4 @@
"unique": 0,
"width": null
}
]
]

View File

@@ -147,7 +147,8 @@ website_route_rules = [
{"from_route": "/courses/<course>/subgroups/<cohort>/<subgroup>", "to_route": "cohorts/subgroup"},
{"from_route": "/courses/<course>/subgroups/<cohort>/<subgroup>/<page>", "to_route": "cohorts/subgroup"},
{"from_route": "/courses/<course>/join/<cohort>/<subgroup>/<invite_code>", "to_route": "cohorts/join"},
{"from_route": "/users", "to_route": "profiles/profile"}
{"from_route": "/users", "to_route": "profiles/profile"},
{"from_route": "/jobs/<job>", "to_route": "jobs/job"}
]
website_redirects = [

0
school/job/__init__.py Normal file
View File

View File

View File

@@ -0,0 +1,8 @@
// Copyright (c) 2021, Frappe and contributors
// For license information, please see license.txt
frappe.ui.form.on('Job Opportunity', {
// refresh: function(frm) {
// }
});

View File

@@ -0,0 +1,154 @@
{
"actions": [],
"allow_rename": 1,
"autoname": "format: JOB-{#####}",
"creation": "2021-12-27 16:53:32.316215",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"job_title",
"location",
"column_break_5",
"type",
"status",
"job_opportunity_status",
"section_break_6",
"description",
"company_details_section",
"company_name",
"company_website",
"column_break_11",
"company_logo",
"application_link"
],
"fields": [
{
"fieldname": "job_title",
"fieldtype": "Data",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Job Title",
"reqd": 1
},
{
"fieldname": "location",
"fieldtype": "Data",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Location",
"reqd": 1
},
{
"fieldname": "column_break_5",
"fieldtype": "Column Break"
},
{
"fieldname": "type",
"fieldtype": "Select",
"label": "Type",
"options": "Full Time\nPart Time\nFreelance\nContract",
"reqd": 1
},
{
"default": "Pending",
"fieldname": "status",
"fieldtype": "Select",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Status",
"options": "Pending\nApproved\nRejected"
},
{
"default": "Open",
"fieldname": "job_opportunity_status",
"fieldtype": "Select",
"label": "Job Opportunity Status",
"options": "Open\nClosed"
},
{
"fieldname": "section_break_6",
"fieldtype": "Section Break"
},
{
"fieldname": "description",
"fieldtype": "Text Editor",
"label": "Description",
"reqd": 1
},
{
"fieldname": "company_details_section",
"fieldtype": "Section Break",
"label": "Company Details"
},
{
"fieldname": "company_name",
"fieldtype": "Data",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Company Name",
"reqd": 1
},
{
"fieldname": "company_website",
"fieldtype": "Data",
"label": "Company Website",
"reqd": 1
},
{
"fieldname": "column_break_11",
"fieldtype": "Column Break"
},
{
"fieldname": "company_logo",
"fieldtype": "Attach Image",
"label": "Company Logo"
},
{
"fieldname": "application_link",
"fieldtype": "Data",
"label": "Application Form Link",
"reqd": 1
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-12-30 12:10:08.849547",
"modified_by": "Administrator",
"module": "Job",
"name": "Job Opportunity",
"naming_rule": "Expression",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"select": 1,
"share": 1,
"write": 1
},
{
"create": 1,
"email": 1,
"export": 1,
"if_owner": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "All",
"select": 1,
"share": 1,
"write": 1
}
],
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"title_field": "job_title"
}

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2021, Frappe and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class JobOpportunity(Document):
pass

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2021, Frappe and Contributors
# See license.txt
# import frappe
import unittest
class TestJobOpportunity(unittest.TestCase):
pass

View File

View File

@@ -0,0 +1,28 @@
{
"attach_print": 0,
"channel": "Email",
"creation": "2021-12-30 12:29:56.533903",
"days_in_advance": 0,
"docstatus": 0,
"doctype": "Notification",
"document_type": "Job Opportunity",
"enabled": 1,
"event": "New",
"idx": 0,
"is_standard": 1,
"message": "Hey,\n\nA new Job Opportunity has been created. \n\n<p>Company Name: {{ doc.company_name}}</p>\n<p>Job Title: {{ doc.job_title}}</p>\n<p>Job Location: {{ doc.location}}</p><br>\n<p>Job Description: {{ doc.description}}</p><br>\n\n<p>Find all the posted jobs <a href=\"{{ frappe.utils.get_url() }}/app/job-opportunity\">here</a>.</p><br>\n",
"modified": "2021-12-30 12:54:13.382512",
"modified_by": "Administrator",
"module": "Job",
"name": "New job alert",
"owner": "Administrator",
"recipients": [
{
"receiver_by_role": "System Manager"
}
],
"send_system_notification": 0,
"send_to_all_assignees": 0,
"sender_email": "",
"subject": "New job added by {{ doc.company_name}}"
}

View File

@@ -0,0 +1,10 @@
Hey,
A new Job Opportunity has been created.
<p>Company Name: {{ doc.company_name}}</p>
<p>Job Title: {{ doc.job_title}}</p>
<p>Job Location: {{ doc.location}}</p><br>
<p>Job Description: {{ doc.description}}</p><br>
<p>Find all the posted jobs <a href="{{ frappe.utils.get_url() }}/app/job-opportunity">here</a>.</p><br>

View File

@@ -0,0 +1,5 @@
import frappe
def get_context(context):
# do your magic here
pass

View File

View File

@@ -0,0 +1,7 @@
frappe.ready(function() {
frappe.web_form.after_save = () => {
setTimeout(() => {
window.location.href = `/jobs`;
})
}
})

View File

@@ -0,0 +1,151 @@
{
"accept_payment": 0,
"allow_comments": 0,
"allow_delete": 0,
"allow_edit": 1,
"allow_incomplete": 0,
"allow_multiple": 1,
"allow_print": 0,
"amount": 0.0,
"amount_based_on_field": 0,
"apply_document_permissions": 1,
"button_label": "Save",
"creation": "2021-12-27 17:02:12.461145",
"custom_css": "[data-doctype=\"Web Form\"] {\n max-width: 720px;\n margin: 6rem auto;\n}",
"doc_type": "Job Opportunity",
"docstatus": 0,
"doctype": "Web Form",
"idx": 0,
"is_standard": 1,
"login_required": 1,
"max_attachment_size": 0,
"modified": "2021-12-30 12:09:22.469041",
"modified_by": "Administrator",
"module": "Job",
"name": "job-opportunity",
"owner": "Administrator",
"payment_button_label": "Buy Now",
"published": 1,
"route": "job-opportunity",
"route_to_success_link": 1,
"show_attachments": 0,
"show_in_grid": 0,
"show_sidebar": 0,
"sidebar_items": [],
"success_message": "",
"success_url": "/jobs",
"title": "Job Opportunity",
"web_form_fields": [
{
"allow_read_on_all_link_options": 0,
"fieldname": "job_title",
"fieldtype": "Data",
"hidden": 0,
"label": "Job Title",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 1,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "location",
"fieldtype": "Data",
"hidden": 0,
"label": "Location",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 1,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "type",
"fieldtype": "Select",
"hidden": 0,
"label": "Type",
"max_length": 0,
"max_value": 0,
"options": "Full Time\nPart Time\nFreelance\nContract",
"read_only": 0,
"reqd": 1,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"default": "Open",
"fieldname": "job_opportunity_status",
"fieldtype": "Select",
"hidden": 0,
"label": "Job Opportunity Status",
"max_length": 0,
"max_value": 0,
"options": "Open\nClosed",
"read_only": 0,
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "company_name",
"fieldtype": "Data",
"hidden": 0,
"label": "Company Name",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 1,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "company_website",
"fieldtype": "Data",
"hidden": 0,
"label": "Company Website",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 1,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "company_logo",
"fieldtype": "Attach Image",
"hidden": 0,
"label": "Company Logo",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "application_link",
"fieldtype": "Data",
"hidden": 0,
"label": "Application Form Link",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 1,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "description",
"fieldtype": "Text Editor",
"hidden": 0,
"label": "Description",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 1,
"show_in_filter": 0
}
]
}

View File

@@ -0,0 +1,5 @@
import frappe
def get_context(context):
# do your magic here
pass

View File

@@ -14,12 +14,14 @@ frappe.ready(function () {
frappe.web_form.validate = () => {
let information_missing;
const data = frappe.web_form.get_values();
data.work_experience && data.work_experience.length && data.work_experience.forEach(exp => {
if (!exp.current && !exp.to_date) {
information_missing = true
frappe.msgprint('To Date is mandatory in Work Experience.');
}
});
if (data && data.work_experience && data.work_experience.length) {
data.work_experience.forEach(exp => {
if (!exp.current && !exp.to_date) {
information_missing = true
frappe.msgprint('To Date is mandatory in Work Experience.');
}
});
}
if (information_missing)
return false;

View File

@@ -21,7 +21,7 @@
"is_standard": 1,
"login_required": 1,
"max_attachment_size": 0,
"modified": "2021-12-21 15:50:31.707751",
"modified": "2021-12-28 16:09:47.675523",
"modified_by": "Administrator",
"module": "LMS",
"name": "profile",
@@ -455,6 +455,18 @@
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "looking_for_job",
"fieldtype": "Check",
"hidden": 0,
"label": "I am looking for a job",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"description": "Private Information includes your Mobile Number, Email Address, Grade Type, Grade and Work Environment Preferences",

View File

@@ -9,7 +9,7 @@
<div class="course-card-pills">{{ tag }}</div>
{% endfor %}
{% if membership and not read_only %}
{% if progress < 100 %}  <div class="course-card-pills dark-pills ml-auto">{{ frappe.utils.rounded(progress) }}%
{% if progress < 100 %} <div class="course-card-pills dark-pills ml-auto">{{ frappe.utils.rounded(progress) }}%
{{ _("Completed") }}
</div>
{% else %}
@@ -39,7 +39,7 @@
</span>
{% endif %}
</div>
<div class="course-card-title">{{ course.title }}</div>
<div class="card-heading course-card-title">{{ course.title }}</div>
<div {% if not read_only %} class="mb-4" {% endif %}>
<span class="zindex">
{{ widgets.Avatar(member=course.get_instructor(), avatar_class="avatar-small") }}

View File

@@ -2,4 +2,5 @@ Community
Hackathon
LMS
Conference
Event Management
Event Management
Job

View File

@@ -47,6 +47,9 @@ input[type=checkbox] {
position: relative;
top: 1rem;
left: 1rem;
}
.course-image .course-tags {
width: 95%;
}
@@ -114,20 +117,23 @@ input[type=checkbox] {
}
}
.course-card-title {
.card-heading {
font-weight: 600;
font-size: 18px;
font-size: 1.5rem;
line-height: 156%;
letter-spacing: -0.014em;
color: var(--text-color-dark);
align-self: stretch;
}
.course-card-title {
font-size: 1.125rem;
margin-bottom: 1.5rem;
height: 56px;
}
@media (max-width: 360px) {
.course-card-title {
font-size: 14px;
.card-heading {
font-size: 0.875rem;
}
}
@@ -1119,7 +1125,7 @@ input[type=checkbox] {
margin-top: 3rem;
}
.institute-name {
.bold-title {
font-weight: bold;
color: var(--text-color-dark);
}
@@ -1463,3 +1469,23 @@ pre {
width: 50%;
justify-content: space-between;
}
.job-card {
display: flex;
justify-content: space-between;
align-items: center;
padding-right: 1rem;
}
.job-card-info {
padding: 2rem 1rem 1rem;
}
.job-description-section {
padding: 1rem;
}
.company-logo {
background-position: left;
background-size: 88px;
}

View File

@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 5.625V14" stroke="#192734" stroke-miterlimit="10" stroke-linecap="round"/>
<path d="M14.125 3.5C12.951 3.5 12 4.45 12 5.625C12 4.451 11.05 3.5 9.875 3.5H4.5C4.23478 3.5 3.98043 3.60536 3.79289 3.79289C3.60536 3.98043 3.5 4.23478 3.5 4.5V16.375C3.5 16.9054 3.71071 17.4141 4.08579 17.7892C4.46086 18.1643 4.96957 18.375 5.5 18.375H9.875C11.049 18.375 12 19.325 12 20.5C12 19.326 12.95 18.375 14.125 18.375H18.5C19.0304 18.375 19.5391 18.1643 19.9142 17.7892C20.2893 17.4141 20.5 16.9054 20.5 16.375V4.5C20.5 4.23478 20.3946 3.98043 20.2071 3.79289C20.0196 3.60536 19.7652 3.5 19.5 3.5H14.125Z" stroke="#192734" stroke-miterlimit="10" stroke-linecap="square"/>
</svg>

After

Width:  |  Height:  |  Size: 783 B

View File

View File

@@ -0,0 +1,34 @@
{% extends "templates/base.html" %}
{% from "www/hackathons/macros/card.html" import null_card %}
{% block title %}{{ _('Job Openings') }}{% endblock %}
{% block content %}
<div class="common-page-style">
<div class="container">
<a class="button is-primary pull-right" href="/job-opportunity">{{ _("Post a Job") }}</a>
<div class="course-home-headings">{{ _("Job Openings") }}</div>
<div class="cards-parent">
{% for job in jobs %}
<div class="common-card-style course-card">
<div class="job-card">
<div>
<div class="course-tags">
<div class="course-card-pills">{{ _(job.type) }}</div>
<div class="course-card-pills">{{ job.location }}</div>
</div>
<div class="job-card-info">
<div class="bold-title">{{ _(job.job_title) }}</div>
<small>{{ job.company_name }}</small>
</div>
</div>
<div class="avatar avatar-large" title="{{ job.company_name}}">
<span class="avatar-frame company-logo" style="background-image: url( {{ job.company_logo | urlencode }} );"></span>
</div>
</div>
<a class="stretched-link" href="/jobs/{{ job.name }}"></a>
</div>
{% endfor %}
</div>
</div>
</div>
{% endblock %}

14
school/www/jobs/index.py Normal file
View File

@@ -0,0 +1,14 @@
import frappe
def get_context(context):
context.jobs = frappe.get_all("Job Opportunity",
{
"status": "Approved",
"job_opportunity_status": "Open"
},
[
"job_title", "location", "type", "company_name",
"company_logo", "name"
],
order_by="creation desc")

43
school/www/jobs/job.html Normal file
View File

@@ -0,0 +1,43 @@
{% extends "templates/base.html" %}
{% from "www/hackathons/macros/card.html" import null_card %}
{% block title %}{{ _(job.job_title) }}{% endblock %}
{% block content %}
<div class="common-page-style">
<div class="container">
{{ BreadCrumb(job) }}
<div class="common-card-style thread-card">
<div class="job-card">
<div>
<span class="course-tags">
<div class="course-card-pills">{{ _(job.type) }}</div>
<div class="course-card-pills">{{ job.location }}</div>
</span>
<div class="job-card-info">
<div class="card-heading">{{ _(job.job_title) }}</div>
<a class="dark-links" href="{{ job.company_website }}">{{ job.company_name }}</a>
<div class="small mt-1">Posted On: {{ frappe.utils.format_date(job.creation, "medium") }}</div>
</div>
</div>
<div class="avatar avatar-large" title="{{ job.company_name}}">
<span class="avatar-frame company-logo" style="background-image: url( {{ job.company_logo | urlencode }} );"></span>
</div>
</div>
<div class="job-description-section">
<div>{{ _(job.description) }}</div>
<a class="button is-primary mt-5" href="{{ job.application_link }}">{{ _("Apply Now") }}</a>
</div>
</div>
</div>
</div>
{% endblock %}
{% macro BreadCrumb(job) %}
<div class="breadcrumb">
<a class="dark-links" href="/jobs">{{ _("Job Openings") }}</a>
<img class="ml-1 mr-1" src="/assets/school/icons/chevron-right.svg">
<span class="muted-text">{{ _(job.job_title) }}</span>
</div>
{% endmacro %}

9
school/www/jobs/job.py Normal file
View File

@@ -0,0 +1,9 @@
import frappe
def get_context(context):
try:
job = frappe.form_dict["job"]
except KeyError:
frappe.local.flags.redirect_location = "/jobs"
raise frappe.Redirect
context.job = frappe.get_doc("Job Opportunity", job)

View File

@@ -32,6 +32,9 @@
{% if member.get_authored_courses() | length %}
<div class="creator-badge"> Creator </div>
{% endif %}
{% if member.looking_for_job %}
<div class="creator-badge"> Open Network </div>
{% endif %}
</div>
{% if frappe.session.user == member.email %}
@@ -78,20 +81,20 @@
<div class="common-card-style overview-card small-title">
{% if enrollment %}
<div class="overview-item">
<img class="icon-background mr-1" src="/assets/school/icons/user.svg" />
{{ enrollment }} Enrolled
<img class="icon-background mr-1" src="/assets/school/icons/course.svg" />
{{ enrollment }} {% if enrollment > 1 %} Courses {% else %} Course {% endif %} Taken
</div>
{% endif %}
{% if reviews %}
<div class="overview-item">
<img class="icon-background mr-1" src="/assets/school/icons/rating.svg" />
{{ reviews }} Created
{{ reviews }} {% if reviews > 1 %} Courses {% else %} Course {% endif %} Reviewed
</div>
{% endif %}
{% if mentorship %}
<div class="overview-item">
<img class="icon-background mr-1" src="/assets/school/icons/calendar.svg" />
{{ mentorship }} Mentored
{{ mentorship }} {% if mentorship > 1 %} Courses {% else %} Course {% endif %} Mentored
</div>
{% endif %}
</div>
@@ -288,7 +291,7 @@
<div class="common-card-style profile-card">
{% for edu in member.education %}
<div class="profile-card-row">
<div class="institute-name"> {{ edu.institution_name }} </div>
<div class="bold-title"> {{ edu.institution_name }} </div>
<div class="profile-item"> {{ edu.degree_type }} <span></span> {{ edu.major }}
{% if not member.hide_private %}
<!-- {% if edu.grade_type %} {{ edu.grade_type }} {% endif %} -->
@@ -316,7 +319,7 @@
<div class="common-card-style profile-card">
{% for work in work_details %}
<div class="">
<div class="institute-name"> {{ work.title }} </div>
<div class="bold-title"> {{ work.title }} </div>
<div class="profile-item"> {{ work.company }} </div>
<div> {{ frappe.utils.format_date(work.from_date, "MMM YYYY") }} -
{% if work.to_date %} {{ frappe.utils.format_date(work.to_date, "MMM YYYY") }} {% else %} Present {% endif %} </div>
@@ -336,7 +339,7 @@
<div class="common-card-style profile-card">
{% for cert in member.certification %}
<div class="">
<div class="institute-name"> {{ cert.certification_name }} </div>
<div class="bold-title"> {{ cert.certification_name }} </div>
<div class="profile-item"> {{ cert.organization }} </div>
<div> {{ frappe.utils.format_date(cert.issue_date, "MMM YYYY") }}
{% if cert.expiration_date %} - {{ frappe.utils.format_date(cert.expiration_date, "MMM YYYY") }} {% endif %} </div>