Skip to content

Commit

Permalink
sizzle: User can reference org while starting timer.
Browse files Browse the repository at this point in the history
  • Loading branch information
apoorvapendse committed Nov 25, 2024
1 parent b104633 commit a87b9f6
Show file tree
Hide file tree
Showing 12 changed files with 237 additions and 18 deletions.
5 changes: 5 additions & 0 deletions company/templatetags/custom_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,8 @@
def get_item(dictionary, key):
"""Return the value for `key` in `dictionary`."""
return dictionary.get(key)


@register.filter
def before_dot(value):
return str(value).split(".")[0]
8 changes: 2 additions & 6 deletions company/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,16 +123,12 @@ def post(self, request, *args, **kwargs):
return redirect("/accounts/login/")

user_domain = get_email_domain(user.email)
company_name = data.get("company_name", "").strip().lower()
company_name = data.get("company_name", "")

if user_domain in restricted_domain:
messages.error(request, "Login with company email in order to create the company.")
return redirect("/")

if user_domain != company_name:
messages.error(request, "Company name doesn't match your email domain.")
return redirect("register_company")

if Company.objects.filter(name=company_name).exists():
messages.error(request, "Company already exists.")
return redirect("register_company")
Expand Down Expand Up @@ -516,7 +512,7 @@ def post(self, request, id, *args, **kwargs):
response = requests.get(safe_url, timeout=5)
if response.status_code != 200:
raise Exception
except requests.exceptions.RequestException:
except requests.exceptions.RequestException as e:
messages.error(request, "Domain does not exist.")
return redirect("add_domain", id=id)
except ValueError:
Expand Down
21 changes: 20 additions & 1 deletion website/api/views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import json
import uuid
from datetime import datetime
from urllib.parse import urlparse

from django.conf import settings
from django.contrib.sites.shortcuts import get_current_site
Expand Down Expand Up @@ -846,8 +847,26 @@ class TimeLogViewSet(viewsets.ModelViewSet):
permission_classes = [IsAuthenticated]

def perform_create(self, serializer):
organization_url = self.request.data.get("organization_url")

try:
serializer.save(user=self.request.user)
if organization_url:
parsed_url = urlparse(organization_url)
normalized_url = parsed_url.netloc + parsed_url.path

# Normalize the URL in the Company model (remove the protocol if present)
try:
organization = Company.objects.get(
Q(url__iexact=normalized_url)
| Q(url__iexact=f"http://{normalized_url}")
| Q(url__iexact=f"https://{normalized_url}")
)
except Company.DoesNotExist:
raise ParseError(detail="Organization not found for the given URL.")

# Save the TimeLog with the user and organization (if found, or None)
serializer.save(user=self.request.user, organization=organization)

except ValidationError as e:
raise ParseError(detail=str(e))
except Exception as e:
Expand Down
24 changes: 24 additions & 0 deletions website/migrations/0154_timelog_organization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 5.1.3 on 2024-11-21 13:44

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("website", "0153_delete_contributorstats"),
]

operations = [
migrations.AddField(
model_name="timelog",
name="organization",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="organization",
to="website.company",
),
),
]
17 changes: 17 additions & 0 deletions website/migrations/0155_alter_company_url.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 5.1.3 on 2024-11-22 11:54

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("website", "0154_timelog_organization"),
]

operations = [
migrations.AlterField(
model_name="company",
name="url",
field=models.URLField(unique=True),
),
]
12 changes: 12 additions & 0 deletions website/migrations/0156_merge_20241124_0329.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Generated by Django 5.1.3 on 2024-11-24 03:29

from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("website", "0154_contributors_to_users_20241123_1836"),
("website", "0155_alter_company_url"),
]

operations = []
12 changes: 12 additions & 0 deletions website/migrations/0157_merge_20241124_0808.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Generated by Django 5.1.3 on 2024-11-24 08:08

from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("website", "0155_merge_20241124_0242"),
("website", "0156_merge_20241124_0329"),
]

operations = []
12 changes: 12 additions & 0 deletions website/migrations/0158_merge_20241125_0802.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Generated by Django 5.1.3 on 2024-11-25 08:02

from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("website", "0156_merge_20241124_0722"),
("website", "0157_merge_20241124_0808"),
]

operations = []
6 changes: 5 additions & 1 deletion website/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class Company(models.Model):
name = models.CharField(max_length=255)
description = models.CharField(max_length=500, null=True, blank=True)
logo = models.ImageField(upload_to="company_logos", null=True, blank=True)
url = models.URLField()
url = models.URLField(unique=True)
email = models.EmailField(null=True, blank=True)
twitter = models.CharField(max_length=30, null=True, blank=True)
facebook = models.URLField(null=True, blank=True)
Expand Down Expand Up @@ -876,6 +876,10 @@ class TimeLog(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="timelogs"
)
# associate organization with sizzle
organization = models.ForeignKey(
Company, on_delete=models.CASCADE, related_name="organization", null=True, blank=True
)
start_time = models.DateTimeField()
end_time = models.DateTimeField(null=True, blank=True)
duration = models.DurationField(null=True, blank=True)
Expand Down
11 changes: 10 additions & 1 deletion website/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,16 @@ class Meta:
class TimeLogSerializer(serializers.ModelSerializer):
class Meta:
model = TimeLog
fields = ["id", "user", "start_time", "end_time", "duration", "github_issue_url", "created"]
fields = [
"id",
"user",
"organization",
"start_time",
"end_time",
"duration",
"github_issue_url",
"created",
]
read_only_fields = [
"id",
"user",
Expand Down
113 changes: 105 additions & 8 deletions website/templates/sizzle/time_logs.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<!-- templates/time_logs.html -->
{% extends "base.html" %}
{% load custom_filters %}
{% load static %}
{% block content %}
<script src="https://cdn.tailwindcss.com" defer></script>
<style>
.alert_box{
background-color: #f8d7da;
Expand All @@ -11,6 +13,7 @@
padding: 10px;
margin-top: 10px;
}

</style>
<div class="container mt-12">
<!-- Include the left navigation -->
Expand All @@ -22,7 +25,7 @@
<form id="start-time-log-form" novalidate>
{% csrf_token %}
<div class="form-group">
<label for="github_issue_url">GitHub Issue URL:</label>
<label for="github_issue_url">GitHub Issue URL*</label>
<input type="url"
class="form-control"
id="github_issue_url"
Expand All @@ -36,6 +39,22 @@
</small>
<div class="invalid-feedback">Please provide a valid GitHub Issue URL.</div>
</div>
<div class="form-group">
<label for="organization_search_input">Organization (optional)</label>
<input type="url"
class="form-control"
id="organization_search_input"
name="organization_search_input"
required
pattern="https?://.+"
aria-describedby="orgSearch"
small
id="orgSearch"
class="form-text text-muted">
<small id="orgSearch" class="form-text text-muted">Search for organization</small>
<ul id="search_results" class="max-h-[30vh] overflow-y-scroll">
</ul>
</div>
<button type="submit" class="btn btn-primary" id="start-button">Start Time Log</button>
</form>
{% endif %}
Expand All @@ -50,6 +69,13 @@ <h2>Active Time Log</h2>
target="_blank"
rel="noopener noreferrer">{{ active_time_log.github_issue_url }}</a>
</p>
<p>
Organization:
<a href="https://{{ organization_url }}"
id="active-issue-url"
target="_blank"
rel="noopener noreferrer">{{ organization_url }}</a>
</p>
<p>
Elapsed Time: <span id="elapsed-time">00:00:00</span>
</p>
Expand All @@ -67,6 +93,7 @@ <h2>Existing Time Logs</h2>
<th scope="col">End Time</th>
<th scope="col">Duration</th>
<th scope="col">GitHub Issue URL</th>
<th scope="col">Organization</th>
</tr>
</thead>
<tbody id="time-logs-table-body">
Expand All @@ -75,11 +102,23 @@ <h2>Existing Time Logs</h2>
<tr>
<td>{{ log.start_time|date:"DATETIME_FORMAT" }}</td>
<td>{{ log.end_time|date:"DATETIME_FORMAT" }}</td>
<td>{{ log.duration }}</td>
{% comment %} Only show hours, mins, seconds {% endcomment %}
<td>{{ log.duration|before_dot }}</td>
<td>
<a href="{{ log.github_issue_url }}"
target="_blank"
rel="noopener noreferrer">{{ log.github_issue_url }}</a>
title="{{ log.github_issue_url }}"
rel="noopener noreferrer">{{ log.github_issue_url | slice:"19:"| truncatechars:30 }}</a>
</td>
<td>
{% if log.organization %}
<a href="https://{{ log.organization }}"
target="_blank"
title="{{ log.organization }}"
rel="noopener noreferrer">{{ log.organization }}</a>
{% else %}
<span>-</span>
{% endif %}
</td>
</tr>
{% endif %}
Expand Down Expand Up @@ -124,6 +163,50 @@ <h2>Existing Time Logs</h2>
let timeLogId = null;
let timerInterval = null;


const organizations_list = {{organizations_list | safe}}
console.log(organizations_list)

// Handle organization search
$("#organization_search_input").on("input", function () {
const searchTerm = $(this).val().trim().toLowerCase();
let searchResults = [];

if (searchTerm !== "") {
searchResults = organizations_list.filter(function (item) {
return item.name.toLowerCase().includes(searchTerm);
});
}

// Update the search results display
$("#search_results").empty();
if (searchResults.length > 0) {
$.each(searchResults, function (index, result) {
const listItem = $("<li class='font-bold border-2 cursor-pointer p-2 rounded-xl m-2 transition-all hover:opacity-80 hover:bg-red-100'>")
.text(result.name)
.on("click", function () {
// Set the clicked item as the search box value
$("#organization_search_input").val(result.url);
$("#search_results").html(`Selected organization: ${result.name} 🔎`);
});

const urlTag = $("<small class='block text-gray-500'>").text(result.url);

listItem.append(urlTag);

// Add the list item to the search results container
$("#search_results").append(listItem);
});
} else {
if (searchTerm !== "") {
$("#search_results").text("No results found");
} else {
$("#search_results").empty();
}
}
});


// Initialize active time log if exists
{% if active_time_log %}
timeLogId = {{ active_time_log.id }};
Expand Down Expand Up @@ -164,16 +247,30 @@ <h2>Existing Time Logs</h2>
$('#start-time-log-form').on('submit', function(event){
event.preventDefault();
const githubIssueUrl = $('#github_issue_url').val().trim();

// Simple URL validation
const urlPattern = /^https?:\/\/github\.com\/[^\/]+\/[^\/]+\/issues\/\d+$/;
if (!urlPattern.test(githubIssueUrl)) {
const organizationURL = $('#organization_search_input').val().trim();

// Simple URL validation for github and organization
const githubUrlPattern = /^https?:\/\/github\.com\/[^\/]+\/[^\/]+\/issues\/\d+$/;
if (!githubUrlPattern.test(githubIssueUrl)) {
// Display an alert message
$('#message-container').html(`<div class="alert_box" role="alert">
Please provide a valid GitHub Issue URL.
</div>`);
return;
}
//only check organizationURL if it is entered
const organizationUrlPattern = /^(https?:\/\/)?[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
if (organizationURL &&!organizationUrlPattern.test(organizationURL)) {
// Display an alert message
$('#message-container').html(`<div class="alert_box" role="alert">
Please provide a valid Organization URL.
</div>`);
return;
}
let ajaxdata={
'github_issue_url': githubIssueUrl,
'organization_url': organizationURL
}

$.ajax({
url: apiBaseUrl + 'start/',
Expand All @@ -182,7 +279,7 @@ <h2>Existing Time Logs</h2>
'Authorization': `Token ${token}`,
'Content-Type': 'application/json'
},
data: JSON.stringify({ 'github_issue_url': githubIssueUrl }),
data: JSON.stringify(ajaxdata),
success: function(data){
location.reload();
},
Expand Down
Loading

0 comments on commit a87b9f6

Please sign in to comment.