Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement exporting of all company interest data to a csv file #3231

Merged
merged 2 commits into from
Mar 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 22 additions & 0 deletions lego/apps/companies/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,17 @@ class COMPANY_TYPES(models.TextChoices):
GOVERNMENTAL = "company_types_governmental"


TRANSLATED_COMPANY_TYPES = {
COMPANY_TYPES.SMALL_CONSULTANT: "Liten Konsulentbedrift",
COMPANY_TYPES.MEDIUM_CONSULTANT: "Medium konsulentbedrift",
COMPANY_TYPES.LARGE_CONSULTANT: "Stor konsulentbedrift",
COMPANY_TYPES.INHOUSE: "Inhouse",
COMPANY_TYPES.TYPES_OTHERS: "Annet",
COMPANY_TYPES.START_UP: "Start-up",
COMPANY_TYPES.GOVERNMENTAL: "Statlig",
}


class COMPANY_COURSE_THEMES(models.TextChoices):
SECURITY = "company_survey_security"
AI = "company_survey_ai"
Expand All @@ -107,6 +118,17 @@ class COMPANY_COURSE_THEMES(models.TextChoices):
FINTECH = "company_survey_fintech"


TRANSLATED_COURSE_THEMES = {
COMPANY_COURSE_THEMES.SECURITY: "Sikkerhet",
COMPANY_COURSE_THEMES.AI: "Kunstlig intellligens",
COMPANY_COURSE_THEMES.DATA: "Big data",
COMPANY_COURSE_THEMES.END: "Front end/Back end",
COMPANY_COURSE_THEMES.IOT: "Internet of things",
COMPANY_COURSE_THEMES.GAMEDEV: "Spillutvikling",
COMPANY_COURSE_THEMES.SOFTSKILLS: "Softskills",
COMPANY_COURSE_THEMES.FINTECH: "Finansiell teknologi",
}

CONTACT_IN_OSLO = "contact_in_oslo"
INTERESTED = "interested"
NOT_INTERESTED = "not_interested"
Expand Down
62 changes: 28 additions & 34 deletions lego/apps/companies/fixtures/test_company_interest.yaml
Original file line number Diff line number Diff line change
@@ -1,66 +1,60 @@
- model: companies.Semester
pk: 1
fields:
semester: 'spring'
semester: "spring"
year: 2017

- model: companies.Semester
pk: 2
fields:
semester: 'autumn'
semester: "autumn"
year: 2017

- model: companies.Semester
pk: 3
fields:
semester: 'spring'
semester: "spring"
year: 2018

- model: companies.Semester
pk: 4
fields:
semester: 'autumn'
semester: "autumn"
year: 2018

- model: companies.CompanyInterest
pk: 1
fields:
company_name: 'BEKK'
contact_person: 'Bekksen'
mail: 'bekk@bekksen.no'
semesters: [1,4]
events: [
'company_presentation',
'course',
'lunch_presentation',
'breakfast_talk',
]
other_offers: ['labamba_sponsor']
comment: 'webkom webkom'
company_name: "BEKK"
contact_person: "Bekksen"
mail: "bekk@bekksen.no"
semesters: [1, 4]
company_type: "company_types_inhouse"
events:
["company_presentation", "course", "lunch_presentation", "breakfast_talk"]
other_offers: ["labamba_sponsor"]
comment: "webkom webkom"

- model: companies.CompanyInterest
pk: 2
fields:
company_name: 'Itera'
contact_person: 'Iteraz'
mail: 'bekk@itera.no'
company_name: "Itera"
contact_person: "Iteraz"
mail: "bekk@itera.no"
semesters: [1, 2, 3, 4]
events: [
'company_presentation',
'course',
'breakfast_talk',
]
other_offers: ['itdagene']
comment: 'webkom webkom webkom'
company_type: "company_types_inhouse"
events: ["company_presentation", "course", "breakfast_talk"]
other_offers: ["itdagene"]
comment: "webkom webkom webkom"

- model: companies.CompanyInterest
pk: 1
fields:
company_name: 'Capra'
contact_person: 'Caprius'
mail: 'caprius@capra.no'
semesters: [2,3]
events: ['bedex', 'other']
other_offers: ['collaboration', 'readme']
comment: 'webkom'

company_name: "Capra"
contact_person: "Caprius"
mail: "caprius@capra.no"
semesters: [2, 3]
company_type: "company_types_inhouse"
events: ["bedex", "other"]
other_offers: ["collaboration", "readme"]
comment: "webkom"
35 changes: 35 additions & 0 deletions lego/apps/companies/tests/test_company_interest.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ def _get_detail_company_interest(pk):
return reverse("api:v1:company-interest-detail", kwargs={"pk": pk})


def _get_export_company_interest():

return reverse("api:v1:company-interest-csv")


class ListCompanyInterestTestCase(BaseAPITestCase):
fixtures = [
"test_abakus_groups.yaml",
Expand All @@ -74,6 +79,36 @@ def test_list_with_bedkom_user(self):
self.assertEqual(company_interest_list_response.status_code, status.HTTP_200_OK)
self.assertTrue(len(company_interest_list_response.json()["results"]))

def test_export_to_csv_with_abakus_user(self):
AbakusGroup.objects.get(name="Abakus").add_user(self.abakus_user)
self.client.force_authenticate(self.abakus_user)
company_interest_export_responce = self.client.get(
_get_export_company_interest()
)
self.assertEqual(
company_interest_export_responce.status_code, status.HTTP_403_FORBIDDEN
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should test for both cases, so a 200 response as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't manage to find out how make a request in the reverse() function that includes the query parameters "year" and "semester". Could you give me some tips.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you can make a new reverse function for that, but you shouldn't need to. The reverse function is based on what is defined in the urls, but to send a valid response you only need to manipulate the query params (from the view).

If you take the reverse url you have already used and append "?year=2023&semester=whatnot", from a Bedkom-user you should get a valid response.
You have some discussions of different ways to do it here https://stackoverflow.com/questions/4995279/including-a-querystring-in-a-django-core-urlresolvers-reverse-call

)

def test_export_to_csv_with_bedkom_user(self):
AbakusGroup.objects.get(name="Bedkom").add_user(self.abakus_user)
self.client.force_authenticate(self.abakus_user)
company_interest_export_responce = self.client.get(
f"{_get_export_company_interest()}?year=2017&semester=autumn"
)
self.assertEqual(
company_interest_export_responce.status_code, status.HTTP_200_OK
)

def test_export_to_csv_with_missing_query_parameters(self):
AbakusGroup.objects.get(name="Bedkom").add_user(self.abakus_user)
self.client.force_authenticate(self.abakus_user)
company_interest_export_responce = self.client.get(
_get_export_company_interest()
)
self.assertEqual(
company_interest_export_responce.status_code, status.HTTP_400_BAD_REQUEST
)


class CreateCompanyInterestTestCase(BaseAPITestCase):
fixtures = [
Expand Down
155 changes: 153 additions & 2 deletions lego/apps/companies/views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
from rest_framework import viewsets
import csv

from django.core.exceptions import ObjectDoesNotExist
from django.http import HttpResponse
from rest_framework import status, viewsets
from rest_framework.decorators import action
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin
from rest_framework.response import Response

from lego.apps.companies.filters import CompanyInterestFilterSet, SemesterFilterSet
from lego.apps.companies.models import (
Expand All @@ -26,6 +32,16 @@
SemesterStatusSerializer,
)
from lego.apps.permissions.api.views import AllowedPermissionsMixin
from lego.apps.permissions.constants import EDIT

from .constants import (
SPRING,
TRANSLATED_COLLABORATIONS,
TRANSLATED_COMPANY_TYPES,
TRANSLATED_COURSE_THEMES,
TRANSLATED_EVENTS,
TRANSLATED_OTHER_OFFERS,
)


class AdminCompanyViewSet(AllowedPermissionsMixin, viewsets.ModelViewSet):
Expand Down Expand Up @@ -56,7 +72,6 @@ class CompanyViewSet(
def get_serializer_class(self):
if self.action == "list":
return CompanyListSerializer

return CompanyDetailSerializer
Arashfa0301 marked this conversation as resolved.
Show resolved Hide resolved


Expand Down Expand Up @@ -126,3 +141,139 @@ def get_serializer_class(self):
elif self.action in ["create", "update", "partial_update"]:
return CompanyInterestCreateAndUpdateSerializer
return CompanyInterestSerializer

@action(detail=False, methods=["GET"])
def csv(self, *args, **kwargs):
user = self.request.user
is_admin = user.has_perm(EDIT, obj=Company)
if not is_admin:
return Response(status=status.HTTP_403_FORBIDDEN)

year = self.request.query_params.get("year")
semester = self.request.query_params.get("semester")
event = self.request.query_params.get("event")

try:
semester = Semester.objects.get(year=year, semester=semester)
except ObjectDoesNotExist:
return Response(status=status.HTTP_400_BAD_REQUEST)

companyInterests = CompanyInterest.objects.filter(semesters__in=[semester])
if event:
companyInterests = companyInterests.filter(events__contains=[event])

event_string = f"-{event}" if event else ""
response = HttpResponse(content_type="text/csv")
response[
"Content-Disposition"
] = f'attachment; filename="{f"Company-interests-{year}-{semester}{event_string}"}.csv"'

writer = csv.writer(response)
writer.writerow(
[
"Navn på bedrift",
"Kontaktperson",
"E-post",
"Telefonnummer",
"Bedriftsinformasjon",
"Semester",
"Arrangementer",
"Annet",
"Samarbeid",
"Bedriftstype",
"Relevante temaer",
"Kontorer i Trondheim for besøk",
"Klassetrinn",
"Antall deltagere",
"Faglig arrangement kommentar",
"Frokostforedrag kommentar",
"Alternativt arrangement kommentar",
"Start-up kommentar",
"Bedrift-til-bedrift kommentar",
"Lunsjpresentasjon kommentar",
"Bedriftspresentasjon kommentar",
"BedEx kommentarg",
]
)
for companyInterest in companyInterests:
participant_range_start = companyInterest.participant_range_start
participant_range_end = companyInterest.participant_range_end
semesters = ", ".join(
[
f"Vår {semester.year}"
if semester.semester == SPRING
else f"Høst {semester.year}"
for semester in companyInterest.semesters.all()
]
)
events = (
", ".join(
[TRANSLATED_EVENTS[event] for event in companyInterest.events]
)
if companyInterest.events
else ""
)
other_offers = (
", ".join(
[
TRANSLATED_OTHER_OFFERS[offer]
for offer in companyInterest.other_offers
]
)
if companyInterest.other_offers
else ""
)
collaborations = (
", ".join(
[
TRANSLATED_COLLABORATIONS[collab]
for collab in companyInterest.collaborations
]
)
if companyInterest.collaborations
else ""
)
company_course_themes = (
", ".join(
[
TRANSLATED_COURSE_THEMES[course_theme]
for course_theme in companyInterest.company_course_themes
]
)
if companyInterest.company_course_themes
else ""
)
target_grades = (
", ".join([f"{grade}.kl" for grade in companyInterest.target_grades])
if companyInterest.target_grades
else ""
)
company_type = TRANSLATED_COMPANY_TYPES[companyInterest.company_type]
writer.writerow(
[
companyInterest.company_name,
companyInterest.contact_person,
companyInterest.mail,
companyInterest.phone,
companyInterest.comment,
semesters,
events,
other_offers,
collaborations,
company_type,
company_course_themes,
companyInterest.office_in_trondheim,
target_grades,
f"{participant_range_start} - {participant_range_end}",
companyInterest.course_comment,
companyInterest.breakfast_talk_comment,
companyInterest.other_event_comment,
companyInterest.startup_comment,
companyInterest.company_to_company_comment,
companyInterest.lunch_presentation_comment,
companyInterest.company_presentation_comment,
companyInterest.bedex_comment,
]
)

return response