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

Feature/lore wiki page #675

Open
wants to merge 31 commits into
base: dev
Choose a base branch
from
Open

Feature/lore wiki page #675

wants to merge 31 commits into from

Conversation

Gunvor4
Copy link
Contributor

@Gunvor4 Gunvor4 commented Sep 8, 2023

Proposed changes

  • Added a MAKE lore wiki to the internal page, so members can write wiki articles about anything lore in the MAKE universe.

Areas to review closely

Deployment notes

  • After deployment, permissions for the general MAKE group should be changed, so every member of MAKE is able to both view, add, change and delete lore articles.

Checklist

(If any of the points are not relevant, mark them as checked)

  • Remembered to run the makemigrations, makemessages and compilemessages management commands and committed any changes that should be included in this PR
  • Created tests that fail without the changes, if relevant/possible
  • Manually tested that the website UI works as intended with different device layouts
    • (Most common is to test with typical screen sizes for mobile (320-425 px), tablet (768 px) and desktop (1024+ px), which can easily be done with your browser's dev tools)
  • Manually tested that everything works as intended when logged in as different users locally
    • (This can be e.g. anonymous users (i.e. not being logged in), "normal" non-member users, members of different committees, and superusers)
  • Made sure that your code conforms to the code style guides
    • (It's not intended that you read through this whole document, but that you get yourself an overview over its contents, and that you use it as a reference guide / checklist while taking a second look at your code before opening a pull request)
  • Attempted to minimize the number of common code smells
    • (See the comment for the previous checkbox)
  • Added sufficient documentation - e.g. as comments, docstrings or in the README, if suitable
  • Added your changes to the "Unreleased" section of the changelog - mainly the changes that are of particular interest to users and/or developers, if any
  • Added a "Deployment notes" section above, if anything out of the ordinary should be done when deploying these changes to the server
  • Structured your commits reasonably

@Gunvor4 Gunvor4 added the feature New functionality on the page label Sep 8, 2023
@Gunvor4 Gunvor4 self-assigned this Sep 8, 2023
@Gunvor4
Copy link
Contributor Author

Gunvor4 commented Sep 8, 2023

Fullskjermvisning_1
Fullskjermvisning_2
Mobilvisning_1
Mobilvisning_2

@codecov
Copy link

codecov bot commented Sep 8, 2023

Codecov Report

Merging #675 (4d9e2a4) into dev (6f55b7d) will decrease coverage by 0.55%.
The diff coverage is 56.60%.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##              dev     #675      +/-   ##
==========================================
- Coverage   88.16%   87.62%   -0.55%     
==========================================
  Files         152      152              
  Lines        6187     6288     +101     
==========================================
+ Hits         5455     5510      +55     
- Misses        732      778      +46     
Files Coverage Δ
src/internal/admin.py 100.00% <100.00%> (ø)
src/internal/urls.py 100.00% <100.00%> (ø)
src/internal/models.py 90.39% <58.82%> (-3.40%) ⬇️
src/internal/views.py 85.14% <64.15%> (-5.77%) ⬇️
src/internal/forms.py 75.18% <31.03%> (-11.98%) ⬇️

@elisakiv
Copy link
Contributor

elisakiv commented Sep 28, 2023

It looks great, just few comments:

It seems that when the title of an article is one very long word with no spaces, it behaves strangely on mobile. The name does not wrap when it becomes too long so the title continues on one line, past the length of the header.

When the title is long, but does contain spaces, the placement of the edit and delete button is a little awkward.

@elisakiv
Copy link
Contributor

If a users adds an article with a name only consiting of special character, the page crashes.

@elisakiv
Copy link
Contributor

When editing an article with a picture, the button and checkbox for removing the picture behaves a little strangely. The checkbox is not level with the picure name, and the "Clear" button does not fully behave like a button, mainly because the cursor does not become a hand, the user does not receive any feedback that the button was clicked, and it does not look like a button either, it looks like the other text on the page.

@elisakiv
Copy link
Contributor

If the article has a very long name, the title in the menu overlaps with the text of the article that the user has open

@Gunvor4 Gunvor4 changed the base branch from main to dev October 5, 2023 18:04
Created Lore model, modified save() method to always slugify title, set up compression of images, and added new model to Django admin
Made form to be used when adding or changing lore articles
Added URLs and views for viewing the general lore article page and for viewing a particular lore article, for adding new lore article, and changing and deleting existing articles. Modified form_valid() method for the CreateView and the UpdateView, so the page throws an error if a user tries to write a new article on a topic that already exists.
Added new template for viewing lore articles, and added lore wiki to the internal header.
Updated translation files before rebasing
If the name of the lore article is "Dev", it should not be editable and not deletable, so we can tell everyone at MAKE that Dev is the best committee, and there is nothing they can do to change that. Mohaha.
Updated translation files before rebasing
Resolved merge conflicts in changelog
Made changes to burger menu, so that it changes into a cross when open
Added separate CSS code for views on pads and mobile phones
Everyone at MAKE should be able to both view, add, change and delete lore articles. This must be added to permissions for the general MAKE group.
…creens

Changed how the icons for changing and deleting lores are shown on devices with smaller screens. On computers, they are shown floating right of the title of the lore article. On pads and mobile phones, the icons are now shown below the title.
Changed text wrapping of long words, switched from visibility: hidden to display: none to make placement of elements more logical, moved pencil and trash can icon to its own line both for normal screen and for mobile view, changed bottom-paddings.
Commented on checkbox in template, in case future dev members need an explanation
Set max length of main text field of lore articles to 150000 letters, and ran migrations
Added an error to deal with titles only consisting of symbols. Checking if title can be slugified and if it results in a non-empty text string. If not, the error is shown.
Resoved merge conflicts in .po and .mo files
When a title contains an 'ø' or an 'æ', they seem to be left out when the title is slugified. I now fixed this by replacing 'ø' with 'o' and 'æ' with 'ae' before slugifying the title
Copy link
Member

@ddabble ddabble left a comment

Choose a reason for hiding this comment

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

Very nice job! 🤩 Just a few comments 😅

I guess I could comment more on the CSS, but I can potentially wait with that until after you've made some of the changes I suggested below - if you decide to 🙂 (Otherwise, I must admit that I personally don't find CSS code in general to be particularly important to keep polished :))

Finally, it would also be very nice if you could add some (simple) tests for the new code, so that we can feel more secure that it keeps working the way we think it does - both now and after future changes to the codebase 🙂

src/internal/migrations/0028_alter_lore_text.py Outdated Show resolved Hide resolved
src/internal/admin.py Show resolved Hide resolved
src/internal/models.py Outdated Show resolved Hide resolved
src/internal/models.py Outdated Show resolved Hide resolved
src/internal/models.py Outdated Show resolved Hide resolved
src/internal/templates/internal/lore_wiki.html Outdated Show resolved Hide resolved
src/internal/templates/internal/lore_wiki.html Outdated Show resolved Hide resolved
src/internal/templates/internal/lore_wiki.html Outdated Show resolved Hide resolved
src/internal/templates/internal/lore_wiki.html Outdated Show resolved Hide resolved
src/internal/static/internal/css/make_lore.css Outdated Show resolved Hide resolved
Also removed image from model, form and template, since images can now be uploaded by CKEditor. Added javascript file to adjust margins of images uploaded by CKEditor
Renamed files:
lore_wiki.html -> lore_list.html
lore_articles_list.html -> lore_list__article_links.html
make_lore.css -> lore_list.css
Changed placement of html files. Instead of keeping the file lore_list__article_links.html in a separate file called includes, now both this file and lore_list.html has been moved to a folder called lore.
Removed overwritten form_valid methods from views and instead overwriting the clean method in forms.
Changed names of urls in urls.py and views.py:
lore_article -> lore_detail
update_lore -> lore_update
delete_lore -> lore_delete
add_lore -> lore_create
Deleted multiple migration files, and reran makemigrations, so the lore model now only have on migration file
Removed the overwritten get_context_data method, and instead using extra_context
The name previously used for the menu - 'lore_topics' has now been changed to 'all_lore_articles', while the name used for the lore currently being shown - 'lore_article' has been changed to 'shown_lore_article'
models.py:
Altered max_length on the title field, made the slug unique, altered __str__ method, made sure titles start with a capitalized letter, added verbose_name.
views.py:
Added blank lines where requested, changed form_title and back_button_text for LoreFormMixin, LoreCreateView and LoreUpdateView.
Copy link
Member

@ddabble ddabble left a comment

Choose a reason for hiding this comment

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

Just doing a second round after the most recent commits 🙂

I just remembered that I might not have taught you anything about writing tests..? If so, just send a DM to me (or maybe @elisakiv..?) if you'd like some pointers :)

In any case, I wanted to reiterate that it would be great if you could add some (simple) tests for the lore pages, which would both help us feel more secure that the code behaves as we think it does - especially in edge cases - and help future developers understand the intended (main) functionality of the code by showing some typical scenarios in some of the tests - as tests often do. Examples include:

  • That a MAKE member (i.e. a user with some of the lore permissions) is able to view/add/change(/delete?) lore pages (through GET and/or POST requests), but an unprivileged user is not
  • That the slug field has the expected value after submitting various titles
  • That colliding slugs/titles are correctly identified
  • That the slug/title field cannot be empty
  • Anything else that you think would be useful to have tests for 🙂

src/internal/forms.py Show resolved Hide resolved
src/internal/models.py Show resolved Hide resolved
Comment on lines +352 to +357

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['show_article'] = True
context['all_lore_articles'] = Lore.objects.order_by('title')
return context
Copy link
Member

Choose a reason for hiding this comment

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

As explained at the bottom of this comment, functions like get_context_data() with a **kwargs parameter can preferably be structured like this: 🙂

    def get_context_data(self, **kwargs):
        return {
            <other context variables>
            **super().get_context_data(**kwargs),
        }

So:

Suggested change
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['show_article'] = True
context['all_lore_articles'] = Lore.objects.order_by('title')
return context
extra_context = {
'show_article': True,
}
def get_context_data(self, **kwargs):
return {
'all_lore_articles' = Lore.objects.order_by('title'),
**super().get_context_data(**kwargs),
}

('show_article' could also have been placed inside the dict returned in get_context_data(), but I think it's better to have it match the way it's inserted in LoreListView.)

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 saw the previous comment, but frankly I don't understand the advantages of doing it the way you propose, so it's a bit frustrating to have to change something that works when I don't understand why I am changing it. I have now changed it, but I'd appreciate an explanation to why the second version of this code is better than the first.

Copy link
Member

Choose a reason for hiding this comment

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

Sure, that's fair 🙂 So in this case, I guess the explanation has two parts (I'm guessing you were mostly interested in the first half of the second one..?):

  1. "Why move context variables from get_context_data() to extra_context?"

    This is generally because there's less "noise" when reading it (compare e.g. extra_context = {...} to def get_context_data(self, **kwargs): return {...}), and so it's preferable whenever possible - which is the case when the values are constant (e.g. True), but not when they're variable/dynamic (e.g. Lore.objects.order_by('title')).

    In this case, however, one of the values is constant, while the other is variable, and so having both extra_context and get_context_data() can make the code even noisier, but it can also be worth keeping the constant and variable variables separated, for the sake of organization - it's hard to say that either approach will always be the best choice 🤷 But since LoreListView already has an extra_context with 'show_article', I think it's best to have its "sister view", LoreDetailView, match that, if that makes sense :)

  2. "Why structure the code inside get_context_data() the way I suggested?"

    This is purely to follow a principle of designing your code to be as future-proof as practically possible (i.e. as long as it doesn't take substantially more effort compared to a "naive" design). To illustrate why I think my suggestion adheres more closely to that principle, take the following example of code that could potentially be written in the future:

    • Writing a test for how the view and/or template behaves when some of the context variables are different (for whatever reason):
      lore_detail_view_instance.get_context_data(show_article=False, all_lore_articles=None)
      This works with the code I suggested, but with the original code, 'show_article' would have been overwritten (or "forced") to always have the value True regardless of the kwargs provided - and likewise for 'all_lore_articles' being overwritten to equal Lore.objects.order_by('title').

    That's what I meant when I said "[...] always let other code calling a context data method to be able to override the values set in the method, using kwargs" in the other comment.

    Also, as an added bonus, PyCharm seems to have a feature of providing code suggestions in templates for the context variables whose names are directly mentioned in the dict literal (i.e. {...}) returned by get_context_data() - but only when we write return {...} and not e.g. context = {...} followed by return context. (This is most likely because it's easier to parse one dict literal you know the location of (i.e. directly following the method's sole return statement), than to somehow analyze which context variables are inserted into context and then later returned 🤷)

Did that explanation make sense? If not, which details was I e.g. too vague about? 🙂

src/internal/forms.py Show resolved Hide resolved
src/internal/forms.py Show resolved Hide resolved
Comment on lines +375 to +379
title = str(self.object)
title = title.replace('ø', 'o')
title = title.replace('æ', 'ae')
slug = slugify(title)
return reverse_lazy('lore_detail', args=[slug])
Copy link
Member

Choose a reason for hiding this comment

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

As mentioned in a comment above, this (and the same method of LoreUpdateView) can be changed to the following after adding get_absolute_url() to Lore:

Suggested change
title = str(self.object)
title = title.replace('ø', 'o')
title = title.replace('æ', 'ae')
slug = slugify(title)
return reverse_lazy('lore_detail', args=[slug])
return self.object.get_absolute_url()

Also, since both the mentioned views' implementations of get_success_url() are completely identical, they can be removed and instead moved to LoreFormMixin 🙂

Comment on lines +389 to +393
title = str(self.get_form_kwargs()['instance'])
title = title.replace('ø', 'o')
title = title.replace('æ', 'ae')
slug = slugify(title)
return reverse_lazy('lore_detail', args=[slug])
Copy link
Member

Choose a reason for hiding this comment

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

This should be possible to replace with:

Suggested change
title = str(self.get_form_kwargs()['instance'])
title = title.replace('ø', 'o')
title = title.replace('æ', 'ae')
slug = slugify(title)
return reverse_lazy('lore_detail', args=[slug])
return self.get_success_url()

permission_required = ('internal.change_lore',)

form_title = _("Change Lore Article")
back_button_text = _("Lore Article")
Copy link
Member

Choose a reason for hiding this comment

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

Perhaps it would be nice to have the back button simply say the title of the article you're editing? 🤔 What do you think?

Suggested change
back_button_text = _("Lore Article")
def get_back_button_text(self):
return self.object.title

@@ -209,7 +209,6 @@ span.no-wrap {
z-index: -1;
}


Copy link
Member

Choose a reason for hiding this comment

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

This change can be reset :)

@ddabble
Copy link
Member

ddabble commented Dec 15, 2023

Btw, regarding the deployment notes in the PR description, it might be wise to not let all members of MAKE delete lore articles, and instead only grant that permission to e.g. the board members - similar to the group permissions for the internal quotes currently on the website 🤔 What do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New functionality on the page
Projects
Status: Ready for Review
Development

Successfully merging this pull request may close these issues.

3 participants