Skip to content

Add json download button - #756

Merged
sbland merged 13 commits into
mainfrom
742-profile-skills-exportimport-buttons/create-json-download-button
Oct 15, 2026
Merged

sbland merged 13 commits into
mainfrom
742-profile-skills-exportimport-buttons/create-json-download-button

Conversation

@sbland

@sbland sbland commented Jul 4, 2026 •

Copy link
Copy Markdown
Contributor

Description

Implements a json download link in addition to the csv download link added previously.

Also improved the share button docs

Fixes #742
Fixes: #770

Type of change

  • Documentation (non-breaking change that adds or improves the documentation)
  • New feature (non-breaking change which adds functionality)
  • Optimization (non-breaking, back-end change that speeds up the code)
  • Technical work (non-breaking, change which is work as part of a new feature)
  • Bug fix (non-breaking change which fixes an issue)
  • Breaking change (whatever its nature)

Key checklist

  • All tests pass (eg. python -m pytest)
  • The documentation builds and looks OK (eg. mkdocs serve)
  • Pre-commit hooks run successfully (eg. pre-commit run --all-files)

Further checks

  • Code is commented, particularly in hard-to-understand areas
  • Tests added or an issue has been opened to tackle that in the future. (Indicate issue here: # (issue))

@codecov

codecov Bot commented Jul 4, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

AdrianDAlessandro

This comment was marked as resolved.

@sbland sbland self-assigned this Aug 13, 2026
@sbland
sbland force-pushed the 742-profile-skills-exportimport-buttons/create-json-download-button branch from 47bd9f7 to 21d0b85 Compare September 20, 2026 19:48
@sbland

sbland commented Sep 20, 2026

Copy link
Copy Markdown
Contributor Author

@AdrianDAlessandro I've rewritten this to us django data endpoint as we discussed instead of using javascript.

This approach doesn't work so well with the shared page so I've disabled the download buttons on that page and added an issue to follow up here: #788

I think this should be ready to merge now but let me know what you think.

@sbland
sbland force-pushed the 742-profile-skills-exportimport-buttons/create-json-download-button branch from 24215c7 to ff20ac5 Compare September 20, 2026 20:27
@sbland sbland assigned AdrianDAlessandro and unassigned sbland Oct 1, 2026

@AdrianDAlessandro AdrianDAlessandro left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This is close. I am happy with the architecture approach. Just a few small details in the views themselves

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

(Not for this PR) I wonder if these snippets of JS scripts should be in a separate folder, or sub folder? They seem like they should be considered a separate category from the HTML snippets that are intended to be in this folder. Perhaps in main/templates/main/snippets/scripts or main/templates/main/scripts?

Comment thread main/views/data_views.py Outdated
Comment thread main/views/data_views.py Outdated
Comment thread main/views/data_views.py Outdated
class DownloadUserSkillDataJSONView(View):
"""A view that returns the user skill data as a JSON file."""

def get(self, request: HttpRequest) -> JsonResponse:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The business logic (of building the dictionary) in this method is the same as for the CSV get method. The difference between them is in how user_skills_data is used later. Can that part of the code be abstracted into a standalone function?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've updated the views to use a mixin and base view. See code comments.

Comment thread tests/main/conftest.py


@pytest.fixture
def client_logged_in(client, user):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Didn't realise we didn't have one of these!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Let me know if you want me to pull out to another PR or just slide in with this one.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No, it's fine to be in this PR. Adding these kinds of thing as and when they're needed makes the most sense to me

Comment thread main/views/account_data_views.py Outdated
from ..models import User as UserType


class _AuthenticatedHttpRequest(HttpRequest):

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@AdrianDAlessandro I added "_" at the start of these so they are not imported into views/init.py which was causing type errors.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

These shouldn't be necessary at all (with importing strategy I mentioned elsewhere). But out of curiosity, what were the type errors?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The type error was something to do with request.user cannot be assigned to User from models

Comment thread main/views/account_data_views.py Outdated

from ..models import User, UserSkill

logger = logging.getLogger(__name__)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@AdrianDAlessandro Some of this is duplicated in account_views.py

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Duplication shouldn't be required if we just import the TermsAcceptedMixin

@sbland
sbland force-pushed the 742-profile-skills-exportimport-buttons/create-json-download-button branch from 340ffd5 to 912bc19 Compare October 14, 2026 11:37
Comment thread main/views/account_data_views.py Outdated
return super().dispatch(request, *args, **kwargs) # type: ignore


class AuthenticatedDataView(_TermsAcceptedMixin, View):

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@AdrianDAlessandro previously these endpoints were not requiring authentication so I've corrected this with a base class

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't think this base class adds anything, just use the TermsAcceptedMixin directly in the view.

Comment thread main/views/account_data_views.py Outdated
request: _AuthenticatedHttpRequest


class DownloadUserSkillDataMixin:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@AdrianDAlessandro I've used a mixin for this but we could have just as easily used a standalone function. Let me know what you think.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think a standalone function is more appropriate here. Mixins are for adding web-specific functionality, but this is just a database accessor

@AdrianDAlessandro

Copy link
Copy Markdown
Collaborator

About to start reviewing this but worth noting there are some merge conflicts to resolve. So get to those ASAP

Added the csv and json download data views that can be accessed from:
- http://localhost:8000/accounts/download-skills-data/csv
- http://localhost:8000/accounts/download-skills-data/json

Also included an optional parameter to the json download to export anonymous json
Also made this togglable as they are no longer valid for the shared skills data view
Changed from
category - competency_domain
subcategory - competency
@sbland
sbland force-pushed the 742-profile-skills-exportimport-buttons/create-json-download-button branch from 912bc19 to cc3824c Compare October 14, 2026 13:13
@sbland

sbland commented Oct 14, 2026

Copy link
Copy Markdown
Contributor Author

@ad

About to start reviewing this but worth noting there are some merge conflicts to resolve. So get to those ASAP

Rebased to resolve conflicts

@AdrianDAlessandro AdrianDAlessandro left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I've made a few suggestions, mainly to just pare back the extra boilerplate added. We really just need that _format_user_skill_data_for_download method as a function to be used in the views as they were structured before. If you want to add the authentication required element, then just import the existing mixin

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't think we need this file. You should be able to import the AuthenticatedHttpRequest and TermsAcceptedMixin straight into data_views.py and make these views require authentication by using that directly as a mixin.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I partly agree except for two points:

  • Importing between views doesn't seem right so perhaps we need a separate shared utils file?
  • We have a separate file for account views so it seemed to make sense to have a separate one for account data views too.

I wasn't sure about having the dataview endpoints redirect to the login page which is what the TermsAcceptedMixin does. This would only actually happen if someone tried to go to the download link directly. I can revert to using the existing mixins.

Comment thread main/views/account_data_views.py Outdated

from ..models import User, UserSkill

logger = logging.getLogger(__name__)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Duplication shouldn't be required if we just import the TermsAcceptedMixin

Comment thread main/views/account_data_views.py Outdated
from ..models import User as UserType


class _AuthenticatedHttpRequest(HttpRequest):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

These shouldn't be necessary at all (with importing strategy I mentioned elsewhere). But out of curiosity, what were the type errors?

Comment thread main/views/account_data_views.py Outdated
return super().dispatch(request, *args, **kwargs) # type: ignore


class AuthenticatedDataView(_TermsAcceptedMixin, View):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't think this base class adds anything, just use the TermsAcceptedMixin directly in the view.

Comment thread main/views/account_data_views.py Outdated
request: _AuthenticatedHttpRequest


class DownloadUserSkillDataMixin:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think a standalone function is more appropriate here. Mixins are for adding web-specific functionality, but this is just a database accessor

Comment thread tests/main/test_account_data_views.py Outdated
from django.urls import reverse


class ViewRequiresAuthenticationMixin:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Should be able to use the LoginRequiredMixin here instead

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

As in the account_data_views.py comments should we extract this class to a separate util file?

@sbland
sbland force-pushed the 742-profile-skills-exportimport-buttons/create-json-download-button branch from a99b2da to ac3b908 Compare October 15, 2026 06:51
@sbland

sbland commented Oct 15, 2026

Copy link
Copy Markdown
Contributor Author

@AdrianDAlessandro I've used the mixins from the account views instead of recreating for the data account views. I've kept the separate file for now but I think some thought needs to go into how these files are arranged. Currenlty we have a separate account_view.py file but this and the page_views.py are both tested in the test_main_views.py file.

@sbland
sbland force-pushed the 742-profile-skills-exportimport-buttons/create-json-download-button branch from 3441c43 to ff557fb Compare October 15, 2026 06:58

@AdrianDAlessandro AdrianDAlessandro left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Great! This is looking good. Just some failing listing checks in pre-commit to fix up and then feel free to merge!

Also, I agree about the overall structure needing some thought / improvement. And definitely we need to improve the consistency between the main folder and the tests folder.

@sbland
sbland merged commit 0da7e7c into main Oct 15, 2026
7 checks passed
@sbland
sbland deleted the 742-profile-skills-exportimport-buttons/create-json-download-button branch October 15, 2026 11:04
@github-project-automation github-project-automation Bot moved this from 👀 In review to ✅ Done in Web App Development Oct 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

Implement a download as json button Profile & skills export/import buttons

2 participants