How to check if notification has been viewed like in facebook? - django

Whenever there are facebook notifications a red indicator appears until the notifications have been viewed for the first time.
How could I implement something similar on my site (preferably with django if anything needs to be done server-side)?

The simplest approach would be:
Have a field in the models for viewed_at which is nullable. Once viewed, set the date. If no value is set, that means the user has not viewed it yet.
If there are multiple users whom this feature needs to be extended to, have a foreign key reference:
class MyViewableObject(models.Model):
#fields
class MyViewableViewedBy(models.Model):
user = models.ForeignKey(User)
viewable = models.ForeignKey(MyViewableObject)
Now, when MyViewableObject is viewed, in the view method, create an association for the request.user in the MyViewableViewedBy model.
The user has not viewed if there is no corresponding user entry for the object in the model MyViewableViewedBy

Related

How to know the user who created a specific item in Django?

Is it possible to get the id of the user who created a specific item, no matter what it, in Django? I have a site where when the users are authenticated can access a form and submit a new item. Can I retrieve who created what without adding an extra 'submitted by'
Event.objects.filter(owner=self.kwargs['pk'])
(which gives me name 'self' is not defined )?
You cannot access the information without adding a new field, but you can have a look at this library django-audit-log for easy tracking. It will add created_by and modified_by fields and maintain them.

How do you set Django permissions based on models linked to a user (and not based on a user's group)?

I have to make a system which will allow users to progressively fill out surveys based on whether or not the initial survey was accepted.
What this means is that after the user has logged in, they need to be able to fill in a preliminary survey for screening purposes. Only once this preliminary screening survey has been approved by an administrative user (superuser) will the user have access to the second (and final) survey.
I have a survey model which looks like this:
class Screening_survey(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=20)
surname = models.Charfield(max_length=20)
salary = models.IntegerField()
is_accepted = models.NullBooleanField()
When the user posts this initial survey, they only fill in the name, surname and salary fields. When the survey is initially posted, 'user' is set to the current logged in user (request.user) and is_accepted is simply set to 'unknown' automatically in the background. It is then up to the administrative superuser to change the is_accepted value to 'yes' or 'no'.
If the value of the is_accepted field is set to yes for a particular user's form, then that user should be able to access the next survey.
I have looked at Django permissions, but I do not think the default permissions will work for me seeing as I don't want users of a specific /group/ to have access to specific pages; rather I want users whose initial surveys have been approved to have access to the next view (the final survey).
I have also given the #user_passes_test decorator some thought, but again it seems as if it checks permissions only on a user basis and not on the basis of a user and a model that is linked to them.
I know this question seems simple -- I'm quite new to Django as well as programming in general).
Thank you for your help.
You're spot on - you will need to define your own logic to see if the user has been approved, not permissions. Permissions don't really allow you to test on a per-user or per-model basis the way you're looking for.
There are two places to define where this test will be. Either in the view itself, or via your own #user_passes_test decorator. You already have a Foreign Key to the user object, so you can write a test in the view, like this:
#login_required
def survey_view(request):
survey = Screening_survey.objects.filter(user=request.user)
if survey and survey.is_accepted is 'yes':
# Do the remaining view logic
else:
raise PermissionDenied
If you want to put this logic in the #user_passes_test, that would work well too. The user object is passed directly (see the docs for an example)

How to set User-based form field choices in a django ModelForm (with django-allauth)

I'm using Django 1.8 and django-allauth. I have a simple form with a dropdown menu that allows my Users to choose a Character model.
I have a UserCharacter model that looks like this:
class UserCharacter(models.Model):
user = models.ForeignKey(User)
character = models.ForeignKey(Character)
is_default = models.BooleanField(default=False)
In my main Form I'm only displaying the "character" field, which appears as a dropdown menu of Character objects. So far, so good - users can select a Character and it is saved as a UserCharacter association.
What I'm trying to do is display all Character objects that don't already have a UserCharacter linked to the currently logged in User. I would normally use the limit_choices_to feature, like so:
character = models.ForeignKey(Character, limit_choices_to={'id__in': UserCharacter.objects.filter(user_id=[USER_ID]))
my problem is, I don't know how to get access to the current user object from the UserCharacter Model or from a ModelForm. I normally need access to the current request to get at the django-allauth logged in user object. normally in place of [USER_ID] is I would put
self.request.user.id
to get the current user's id from django-allauth, but I can't do that from the Model here. How would I go about changing the form choices in the ModelForm based on the current user object?
Thanks so much!
Since this needs the currently logged in user then you have to do it in the View where you override the form characters QuerySet based on your user.
form.character.queryset = Character.objects.filter(....)
You can also pass the request.user to the form and do the filter there in the constructor.

How to restrict editing of records to the logged-in user?

Sorry, I am still new to Django, hopefully the question isn't out of place.
When I have the following in my template:
<td>{{ item.last_name }}</td>
By clicking on last name the user will be redirected to the following link in order to edit it.
http://127.0.0.1:8000/contact/edit/?id=1
But then what prevents any logged in user to just inject a different id in there on the browser and edit a record that doesn't belong to him?
Update
I just had an idea when I read the comment and answer below. Rather than using a third party app, couldn't I just create a UserProfile for each user and attach a unique company wide uuid.uuid1(). Each time a loggedin user attempts to edit something, his unique company uuid will be also passed in the link as an additional parameter.
On the edit side, it would harvest this guid and compare it against the logged in user and see if they match. If they do match, he is authorized to proceed with the editing, otherwise he will be redirected.
What do you think? Any weaknesses?
If you use Django's new class based views, e.g. the generic UpdateView, you can extend the dispatch handler.
def dispatch(self, request, *args, **kwargs):
handler = super(MyEditView, self).dispatch(request, *args, **kwargs)
# Only allow editing if current user is owner
if self.object.author != request.user:
return HttpResponseForbidden(u"Can't touch this.")
return handler
In this case, the code verifies that the author field of the model object corresponds to the currently logged in user, before even handling the rest of the request.
You can see a reallife example of this in a project of mine.
When you're using Django auth, always rely on the session mechanism to identify an user instead of making some other id such as uuid1() (except, for example, when you need extra sessions in an e-commerce site under HTTPS).
For the permission part, you could check the ownership directly, mainly as described by Koliber Services. The relationships between Company, User and Contact are crucial for the logic of permission checking. There are many ways to model the relationships and thus the code would differ much. For example:
# a modeling way
User.company -> Company : an user belongs to a company
Contact.contributor -> User : a contact is contributed by an user, would be invalid is user is leaving the company
# could check accessibility by
can_view = contact.contributor.company_id == current_user.company_id
# another modeling way
User.company -> Company : an user belongs to a company
Contact.company -> Company : a contact info is owned by a company, does not share globally
# could check accessibility by
can_view = contact.company_id == current_user.company_id
When can_view is False, user should get a 403 for his unauthorized attempting and get logged.
Normally the above method is enough for content protection(not yet in Django Admin). However, when you have many different types of permission checking and even row-permission checkings, it's better to use some uniform permission API.
Take Django-guardian for example, you could simply map companies to groups and assign can_view permission for a contact for the group representing the user's company. Or, assign the can_view permission to all users in a company when a contact is created by using signal or celery task.
Furthermore, you could use /contact/1/edit/ instead of /contact/edit/?id=1. In this way the int(request.GET('id')) part is moved to urlconf like r'^contact/(?P<pk>\d+)/$', less code and much clearer.
There are some third-party apps that does what you want, its called "row-level permission" where you can give different users different access to specific objects, "Row level" comes from SQL where each object is a row in the database
I use django-guardian to do the job
In the function handling the saving of the data, check to see if the object being edited has the same ID as the presently logged in user.
For example, if the object in question is called EmailPrefs and it has a field called user_id:
Load the EmailPrefs object with the ID of the object being edited
If the user_id does not match the current user, stop further processing
Modify the EmailPrefs object
Save the EmailPrefs object to the database

Implement auto_current_user_add when using Django's User table

I have an AppEngine app that I'm migrating to run in Django, using app-engine-patch to get all the goodness of Django - particularly the Admin interface.
One of my models looks like (partially) this:
class Request(db.Model):
requestor = db.UserProperty(auto_current_user_add=True)
When I display a form based on this model I don't display the requestor field, and so when I call the Model's put() method the entity I'm saving doesn't have the requestor property set. This triggers the auto_current_user_add magic, and the user who created the request is automatically added.
Under Django, I'm using the provided Users table. I want this to display as a list of the users of my app, so the model becomes:
from ragendja.auth.google_models import User
class Request(db.Model):
requestor = db.ReferenceProperty(User)
However, this breaks the auto_current_user_add magic in the admin interface - if the user of the admin interface doesn't enter a value for the requestor property, Django sets the property to None, when I'd really like for the Request to have their username inserted automatically.
How can I restore the magic?
My solutions relies on three things:
First: it's possible to override the model's put() method.
Second: users.get_current_user() still provides the correct user, and
Third: ragendja.auth.google_models.User.get_djangouser_for_user() takes a google.appengine.api.users.user object and returns the corresponding Django User object - creating it first if it didn't already exist.
Putting this all together, I have:
class Request(db.Model):
requestor = db.ReferenceProperty(User)
def put(self):
if not self.requestor:
self.requestor = User.get_djangouser_for_user(users.get_current_user())
super(Request, self).put()
This works nicely with the admin interface: the admin can assign any existing user (or use the supplied + sign to create a new user) - if they leave it blank, they'll be assigned as the requestor.
Later when I add a view for users to manage their own requests, this value will be on the 'excluded' list, and the same method will add in their username every time they create a new request.
I'm not sure if this is an optimal solution though; I'm new to Django, so maybe there's a better way to achieve this.