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
Log operations #6419
Log operations #6419
Conversation
…sts to accept the message change
…and the move page log
…on spews the correct format
…orking is very ugly
cms/admin/forms.py
Outdated
@@ -5,6 +5,9 @@ | |||
from django.contrib.auth.models import Permission | |||
from django.contrib.contenttypes.models import ContentType | |||
from django.contrib.sites.models import Site | |||
from django.contrib.admin.utils import ( |
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.
single line
cms/admin/pageadmin.py
Outdated
@@ -1221,6 +1246,7 @@ def unpublish(self, request, page_id, language): | |||
page.unpublish(language) | |||
message = _('The %(language)s page "%(page)s" was successfully unpublished') % { | |||
'language': language_name, 'page': page} | |||
|
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.
please avoid cosmetic changes unrelated to pr
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.
Understood. I'll rectify.
cms/utils/log_operations.py
Outdated
@@ -0,0 +1,122 @@ | |||
# -*- coding: utf-8 -*- |
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.
rename to log_entries
cms/utils/log_operations.py
Outdated
""" | ||
|
||
|
||
def create_log(user_id, content_type_id, object_id, object_repr, action_flag, change_message): |
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.
rename to create_log_entry
cms/admin/pageadmin.py
Outdated
@@ -75,6 +75,7 @@ | |||
from cms.utils.admin import jsonify_request | |||
from cms.utils.conf import get_cms_setting | |||
from cms.utils.urlutils import admin_reverse | |||
from cms.utils.log_operations import log_page_change, log_page_move, log_page_delete |
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'm foreseeing issues with the implementations of title, plugins, etc because this is too tied to the admin.
As a result, I think it might be a better approach to use signal handlers and listen for the post_obj_operation signals for pages and post_placeholder_operation signal for placeholders and plugins.
I suggest to create a module called log_entries.py in cms/signals/
and there add all the necessary handlers.
So this won't really change much in your current implementation, other than where the log entry is created.
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.
All of this is fine but falls short for title changes as the signals for these are attached to a page change. No signals are fired specifically to title. One way to achieve this would be to catch a page edit and check what was being changed and log dependant on that. It's not a clean solution.
cms/utils/log_operations.py
Outdated
Page logs | ||
""" | ||
|
||
|
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.
lots of repetition with the page log functions, also I don't think we should have one for each type of entry.
With the signal handler approach I suggested above, maybe create a page specific handler which receives the operation type and then map operation types to action flags.
cms/tests/test_log_operations.py
Outdated
message = '[{"added": {}}]' | ||
self.assertEqual(message, log_entry.change_message) | ||
message = 'Added.' | ||
self.assertEqual(message, log_entry.get_change_message()) |
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.
@czpython how far does the removal of LogEntry dependance need to go i.e.the test for get_change_message is specific to how the admin uses the multi lingual json objects in the change_message field. I sthis test redundant and does that also mean any auto generated messages are also redundant. I'm confused at just how far away this task needs to move away from the Admin LogEntry model.
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.
Good point. We don't need to test get_change_message
.
…operations to page with a CHANGE flag
…e as the source object
… deleted handlers for the Page model.
cms/admin/forms.py
Outdated
token=operation_token, | ||
obj=new_page, | ||
) | ||
|
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.
remove newline
cms/admin/forms.py
Outdated
@@ -443,6 +467,12 @@ def clean(self): | |||
return data | |||
|
|||
def save(self, commit=True): | |||
|
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.
remove newline
cms/admin/forms.py
Outdated
request=self.request, | ||
operation=CHANGE_PAGE, | ||
) | ||
|
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.
remove newline
cms/admin/forms.py
Outdated
request=self.request, | ||
operation=CHANGE_PAGE, | ||
) | ||
|
||
data = self.cleaned_data |
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 would move data = self.cleaned_data
above operation_token
cms/admin/forms.py
Outdated
token=operation_token, | ||
obj=cms_page, | ||
) | ||
|
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.
remove newline
cms/signals/log_entries.py
Outdated
Create a log for the correct placeholder operation type | ||
""" | ||
|
||
request = kwargs.pop('request') |
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.
use .get()
cms/signals/log_entries.py
Outdated
content_type_id = ContentType.objects.get_for_model(page).pk | ||
object_id = page.pk | ||
object_repr = str(page) | ||
|
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.
remove newline
cms/signals/log_entries.py
Outdated
object_id = page.pk | ||
object_repr = str(page) | ||
|
||
create_log_entry(user_id, content_type_id, object_id, object_repr, operation_handler['flag'], operation_handler['message']) |
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.
same as above. kwargs with each arg in one line
cms/signals/log_entries.py
Outdated
operation_handler = _placeholder_operations_map[operation_type] | ||
user_id = request.user.pk | ||
placeholder = kwargs.pop(operation_handler['placeholder_kwarg']) | ||
page = placeholder.page |
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.
will need to check that placeholder actually has page
cms/tests/test_log_entries.py
Outdated
from django.forms.models import model_to_dict | ||
from django.utils.translation import ugettext_lazy as _ | ||
|
||
from cms.api import create_page, add_plugin, create_title |
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.
import order
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 think I can see your style of coding now so new line comments should be few and far between in the future. :-)
cms/admin/pageadmin.py
Outdated
) | ||
return token | ||
operation=operation, | ||
sender=self.__class__, |
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 had initially tried self.model but it wasn't available for some reason. It's possible that one failed so I removed them all for consistency. I'll add them back and test.
cms/signals/log_entries.py
Outdated
} | ||
|
||
|
||
def create_log_entry(user_id, content_type_id, object_id, object_repr, action_flag, change_message): |
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.
Yup. works.
cms/signals/log_entries.py
Outdated
Create a log for the correct page operation type | ||
""" | ||
|
||
request = kwargs.pop('request') |
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 got this from previous examples of how Django CMS fetched the kwargs. A search in all cms files will show all of the examples of "kwargs.pop". I try to follow how the app is already written when possible. :-). I'll update mine to get. ;-)
cms/signals/log_entries.py
Outdated
operation_type = kwargs.pop('operation') | ||
obj = kwargs.pop('obj') | ||
|
||
if operation_type in _page_operations_map: |
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've created a private function to fix this that checks for if the supplied object is a Page or PageType instance. I'm thinking that checking for just Page is OK though. What is the reasoning for an additional PageType check?
cms/admin/pageadmin.py
Outdated
) | ||
return token | ||
operation=operation, | ||
sender=self.__class__, |
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 hope that I've interpreted your comment correctly. I've removed the private class methods and just used the functions directly. This required changing a lot of the calls to fire a signal.
…emoved the spoofed version
@czpython |
cms/admin/pageadmin.py
Outdated
@@ -480,10 +470,12 @@ def delete_view(self, request, object_id, extra_context=None): | |||
return self.render_delete_form(request, context) | |||
|
|||
def delete_model(self, request, obj): | |||
operation_token = self._send_pre_page_operation( | |||
request, | |||
|
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.
remove newline
cms/admin/pageadmin.py
Outdated
) | ||
|
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.
remove newline
@@ -0,0 +1,136 @@ | |||
from django.contrib.admin.models import LogEntry, ADDITION, CHANGE, DELETION |
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.
Missing this
cms/signals/log_entries.py
Outdated
user_id = request.user.pk | ||
content_type_id = ContentType.objects.get_for_model(obj).pk | ||
object_id = obj.pk | ||
object_repr = str(obj) |
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 can be passed directly without declaring var
cms/signals/log_entries.py
Outdated
operation_handler = _page_operations_map[operation_type] | ||
user_id = request.user.pk | ||
content_type_id = ContentType.objects.get_for_model(obj).pk | ||
object_id = obj.pk |
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 can be passed directly without declaring var
cms/signals/log_entries.py
Outdated
# Check that we have instructions for the operation and an instance of Page to link to in the log | ||
if operation_type in _page_operations_map and _is_valid_page_instance(obj): | ||
operation_handler = _page_operations_map[operation_type] | ||
user_id = request.user.pk |
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 can be passed directly without declaring var
cms/signals/log_entries.py
Outdated
operation_type = kwargs.get('operation') | ||
obj = kwargs.get('obj') | ||
|
||
# Check that we have instructions for the operation and an instance of Page to link to in the log |
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.
break this into two lines
cms/signals/log_entries.py
Outdated
""" | ||
Create a log for the correct page operation type | ||
""" | ||
|
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.
avoid newlines after doc strings
cms/signals/log_entries.py
Outdated
# Check that we have an instance of Page to link to in the log | ||
if _is_valid_page_instance(page): | ||
content_type_id = ContentType.objects.get_for_model(page).pk | ||
object_id = page.pk |
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.
see above about passing these directly
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.
All done as per the request.
Summary
The purpose of this PR is to get early feedback on how the logging has been implemented and any ideas / changes that Paulo may require.
Logs are all collected in the cms/utils/log_operations to keep the messages and contents consistent across all operations. It May seem repetitive but allows each log to be unique for different circumstances. The method names aim to make the log being created clear and concise.
Issues with the existing solution:
- A log entry isn't created when a page is created using the new page wizard.
- Difficult to find the log page creation as they are scattered. The existing implementation,uses the LogEntry model directly, others use the ModelAdmin Implementation. There should be one way where possible IMO.
Design Considerations:
- Allow external plugins to integrate with the CMS logger i.e. custom logs, may be useful if the LogEntry method is replaced for a different logging facility??
- A log helper method "create_log" that uses LogEntry and allows the removal of LogEntry at a later date.
- A page move event is recorded as CHANGE with no message. A "Moved." message has been manually added. There is a comment in the code to make this clear.
- Django admin keeps all logs in one area rather than spreading them out and potentially having them set inconsistently and scattered in multiple files.
Links to related discussion
Private documentation