-
Notifications
You must be signed in to change notification settings - Fork 5
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
base: dev
Are you sure you want to change the base?
Conversation
Codecov Report
Additional details and impacted files@@ 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
|
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. |
If a users adds an article with a name only consiting of special character, the page crashes. |
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. |
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 |
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
972bf22
to
6f6f595
Compare
There was a problem hiding this 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 🙂
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.
There was a problem hiding this 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 🙂
|
||
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 |
There was a problem hiding this comment.
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:
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
.)
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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..?):
-
"Why move context variables from
get_context_data()
toextra_context
?"This is generally because there's less "noise" when reading it (compare e.g.
extra_context = {...}
todef 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
andget_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 sinceLoreListView
already has anextra_context
with'show_article'
, I think it's best to have its "sister view",LoreDetailView
, match that, if that makes sense :) -
"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):
This works with the code I suggested, but with the original code,
lore_detail_view_instance.get_context_data(show_article=False, all_lore_articles=None)
'show_article'
would have been overwritten (or "forced") to always have the valueTrue
regardless of the kwargs provided - and likewise for'all_lore_articles'
being overwritten to equalLore.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 byget_context_data()
- but only when we writereturn {...}
and not e.g.context = {...}
followed byreturn 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 solereturn
statement), than to somehow analyze which context variables are inserted intocontext
and then later returned 🤷) - Writing a test for how the view and/or template behaves when some of the context variables are different (for whatever reason):
Did that explanation make sense? If not, which details was I e.g. too vague about? 🙂
title = str(self.object) | ||
title = title.replace('ø', 'o') | ||
title = title.replace('æ', 'ae') | ||
slug = slugify(title) | ||
return reverse_lazy('lore_detail', args=[slug]) |
There was a problem hiding this comment.
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
:
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
🙂
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]) |
There was a problem hiding this comment.
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:
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") |
There was a problem hiding this comment.
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?
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; | |||
} | |||
|
|||
|
There was a problem hiding this comment.
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 :)
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? |
Proposed changes
Areas to review closely
Deployment notes
Checklist
(If any of the points are not relevant, mark them as checked)
makemigrations
,makemessages
andcompilemessages
management commands and committed any changes that should be included in this PR