Custom user dashboard in django - python

I have a system that has two types of users with different privileges, the first user is the admin who can access all objects from the database, the second one is a dealer who can only view information pertaining to them alone.(There are many dealers)
This is how the system iworks: the admin creates a coupon code and issues it to a person (already done) then that person goes to a dealer who is supposed to check if that coupon code exists.
when a dealer logs in he is supposed to be redirected to a dashboard that has the number of items he has sold and to whom. To sell a new item he needs to check if that coupon code exists and if it does then access a form to fill in the item details(I have a model for issued_items)
How would I implement a custom admin page for the dealer without affecting the admin dashboard.
I created a dealer with super-admin and changed his permissions so that he is only able to change specific models, problem is, the models appear with all objects in that model even the ones by other dealers.
I have thought(not tried yet) of creating a view,and a template and redirect login but if i do this then i override the admin
(not so sure)Probably create a new app for the dealer???????

This sounds like a situation where you want the functionality to be loosely coupled to prevent headaches down the road, so I'd go with option 3. Leave the admin for the admins and create a new dealer app for the dealers to go to, with a regular view/model/template that they'll be required to login to see.

I wasn't able to elaborate my question coz am a django newbie, but after a week of trying a lot of different things I found a way out. For the dealers and other non staff users I created a dashboard and also overiding the registration to suit my project.
Its now working fine.

Related

Editing models and extending database structure in Saleor

I recently forked Saleor 2.9 for a web app I am building for an art gallery that wants to display their products for sale as well as give their artists some publicity. I want to be able to have a bunch of cards (like "our team" components) that pull data from an Artists table on the back-end that stores information about the artists' names, emails, origins, etc, and then display it on the front-end. I am struggling to see how to modify the models/DB to create a new "Artists" table with name, email, info, and then to create a manyToMany-like relationship with the products I've populated in the DC, giving the products a "created by" attribute. There are tons of models files throughout the /dashboard directory, and even when I make changes to the core models to create an artist class, I don't know how to get it to show on the dashboard so artists can be created/modified from there.
I would like to make it so that the client (non-technical) can add artists and have them show up on the artists page I will make, somewhat like products show up on their pages (but obviously I cannot create a new category "Artist" as artists cannot have prices or shipping as they are people; and there are other attributes I would want like email that a product cannot have, either. They are also different to staff on the website, so I cannot use the "staff management" functionality.)
I looked at this question but Saleor structure has changed since then, and that was a relatively minor attributal change to an existing class (User) as opposed to the creation and integration of a new class. I'm surprised that despite extensively searching for anything on how to do something as straightforward as create a new model there is little documentation and discussion online; I must be missing something.
Please help :) Thank you!
The django way to create new models, (and SaleorĀ“s backend is django based) is:
You should create a new app on your store backend (the django part of saleor) with:
$ python manage.py startapp artist
Create your Artist model, with all the fields you want such as email, etc... in the file: artist/models.py.
Modify the Product model in the file product/models.py by importing the Artist models and adding a ForeignKey (for example) relationship to it.
Register the new artist app in your settings.py's "INSTALLED_APPS".
Run python manage.py makemigrations... (Check they include your changes to models)
Run python manage.py migrate.
That should be it. 'less I`m forgeting something, in which case, please post back when you have moved forward with this.
Notes:
You may want to back up your DB first.
Also when applying these migrations, django will ask you for a placeholder value for products which where in your DB before Product had an Artist field.
References:
django models
django migrations

Flask - User to Profile Relationships

I'm working with Flask-restplus and I am at a point where I would like to associate each User in my user model to a type of profile, where each user can be associated with one or many profile types. I'm wondering how you guys would go about this. So far, here's what I'm thinking/planning to do. NOTE: I'm not very experienced in web development, so there's a chance I don't know the best way to accomplish this.
Step 1: Create a one-to-many (clients need to also be employees, see below) field (profile_types) relating to a static table that just lists all possible profile options. EXAMPLE:
PK PROFILE TYPE
1 provider
2 employee
3 client
.....
The idea here is to track different information and allow for different views/endpoints for users who are tied to certain profile types. Example, employees would provide a valid login authentication and be directed to page A while a client would be directed to page B, etc. We're also planning on collecting different data points within each profile model.
So an instance of a user might look like this, user1.profile == [client, employee'].
NOTE: This is more important for data collection (ie age of employee, start date, etc) than it is for creating directives based on permissions.
Step 2: Upon creating the new user, a signal fires off the creation of a profile based on the profile_types supplied to the user instance. I've used signals with django in the past, is there a signal library for Flask?
Step 3: An empty profile instance(s) now exists for that user. It will be up to a superuser to upload data in bulk or manually fill out profile information.
Is this a sensible way to go about this? My other though is to create a bunch of Boolean fields in the User model is_provider, is_employee, is_client, etc. All fields that are True get assigned a profile instance. What's the best way to go about this?
Thanks everyone!
Seeing that are you try to validate multiple profile types, you may use
if user.profile_type in ['employee', 'client']
Now, if you want to add an super user I think you can use this
if user.profile_type in ['employee', 'client'] and user.profile_type == 'superuser'
Now, you relationship is more like 'many-to-many', because you are saying that an client also needs to be an employee, if you mean that some endpoints needs to be accessible for employees and clients, then you need to use a 'many-to-one' relationship (an Stackoverflow question which explains what is that)
For your instances, there is Flask Marshmallow, which has an amazing compatibility with Flask SQLAlchemy if you are using an database, but Flask Marshmallow can work alone.

Problems limiting editors to their own content in Wagtail admin

Users that have been assigned to a group with 'add' permissions are able to access, copy, move and add pages created by other users via the admin search or by directly entering the correct path in the browser.
The goal is to prevent users from seeing anything the other users are doing. I had thought it was pretty much implemented.
My page tree looks like this:
Home > Persons > Person Profile > Person Story
Users sign up for an account and are automatically assigned to a custom 'Authors' group. This group has 'add' and 'publish' permissions on the Persons page. The user is responsible for any number of people on their team. With this setup they are able to add a Profile page for each member of their team. Then multiple stories may be added for each person with a profile. Now each Person has subpages of Stories linked to their profile.
I have the page explorer set so users only see their pages:
#hooks.register('construct_explorer_page_queryset')
def show_authors_only_their_articles(parent_page, pages, request):
user_group = request.user.groups.filter(name='Authors').exists()
if user_group:
pages = pages.filter(owner=request.user)
return pages
The image chooser also only displays images uploaded by the user:
#hooks.register('construct_image_chooser_queryset')
def filter_images_by_user(images, request):
images = images.filter(uploaded_by_user=request.user)
return images
And page summary items show only what belongs to the user using similar code.
But during what I thought was going to be final testing, I discovered that a search done using the admin search leads to a list of all available Person Profile and Person Story pages with those search terms. For example if they search for 'John', all Profile and Story page are returned for John. Users may then click on John's Profile page. Once arriving on John's profile page in the explorer they are able to add Stories to John's profile, copy, move or unpublish it! They can do the same with John's stories, minus adding a subpage.
This is a game changer and won't work for us.
I've looked around and see what might be several solutions:
1) Create a similar setup using ModelAdmin but I think I'm going to have the same problem. When searching users will still be able to find and manipulate forbidden content.
2) Create a unique user group for each user as recommended in this post: Wagtail per page user permission
In the second method, after the user is created I would need to programmatically:
1) Create a new user group just for them, maybe using their username.
2) Assign them to the new user group
3) Create a new 'Person' page specific to them and grant them 'add' and 'publish' permissions to it.
The last step because it seems that if I assign them all to the same Person page, they will still be able to add pages to other users Profiles regardless of being in a different user group, since all those different user groups will still have add access to the same Person page.
Ultimately I need to block each user off from what the other users are doing. Your thoughts are much appreciated. It's been years since I've done any programming and I'm still catching up. In the meantime I'm going to start seeing I can come up with.
I think we are pretty close. The system works and flows so well!
I finally figure this one out by searching for instances of GroupPagePermission and GroupCollectionPermission in the Wagtail core package. Was able to piece it together looking at how they did it.
In the models.py of an app I have called 'users' I implemented the django-allauth user_sign_up #receiver. As soon as the user is successfully signed up it runs the below code:
from django.contrib.auth.models import Group, Permission
from django.dispatch import receiver
from allauth.account.signals import user_signed_up
from wagtail.core.models import Page, GroupPagePermission, GroupCollectionPermission, Collection
from article.models import PersonIndexPage
#receiver(user_signed_up)
def create_user_group_and_pages(sender, **kwargs):
"""
When a new user signs up create a unique group and page for them.
Assign it the appropriate permission for admin, page and collection access.
"""
# Grab the new user
user = kwargs['user']
# Create a group object that matches their username
new_group, created = Group.objects.get_or_create(name=user.username)
# Add the new group to the database
user.groups.add(new_group)
# Create new permission to access the wagtail admin
access_admin = Permission.objects.get(codename='access_admin')
# Add the permission to the group
new_group.permissions.add(access_admin)
# Now start creating page access
# First find the homepage
home = Page.objects.get(slug='home').specific
# Create unique PersonIndexPage for the user
person_index_page = PersonIndexPage(title=user.username)
# Add PersonIndexPage to homepage as a child
home.add_child(instance=person_index_page)
# Save new page as first revision
person_index_page.save_revision()
# Create new add GroupPagePermission
GroupPagePermission.objects.create(
group=new_group,
page=person_index_page,
permission_type='add'
)
# Create new GroupCollectionPermission for Profile Images collection
GroupCollectionPermission.objects.create(
group=new_group,
collection=Collection.objects.get(name='Images'),
permission=Permission.objects.get(codename='add_image')
)
Now when a creates a new account a new Index page is created for them that has a unique group created that gives them access to only that Index page and it's child pages. Effectively blocking them from access to any other content on the site. They can still see results to other pages in the admin search but don't have permission to do anything with those results.
Users can log in, create profiles for each person and then as many stories as they want for each person.

Proper way to share temporary data between two users

Here is my case in django,i need to create a match between two users, users take turn, after one of them has finished, i need to send user1 score to user2 and vise versa.
How can i create a match between two players?
How do i store their data(scores) in a way that can be accessed for both users.
Here is what i've tried : user1 sends GET request to get a user2 as a opponent by getting user2 id (i can say i made a match there), then after user1 finished he make another GET request with his id and score to django. and here is where i stuck :
I don't know how to send user1 score to user2.
I don't know how to store the data so both users can access each other score.
I'm quite new to django, so i did all that based on my basic knowledge of the framework, please correct me if i'm wrong and possibly suggest a better approach.
An approach I would take would be to create two models one for Match and the other for turn. Match would contain fields including foreign keys to player_1 and player_2 and the overall score, game active and which players turn it is. The second model I would create would be a turn which has the details of the turn and a foreign key to the match.
Each time a turn occurs it would be a CreateView, see Class based views in the django docs. This will create a new turn, and you should be able to automatically add in the game that it belongs to.
The problem you will have then is then notifying the other user that the new turn has been taken. The simplest way would be to just wait and let the user reload the page but that may lead to a subpar user experience.
The next way would be to create a javascript loop to periodically poll your backend and create an alert when the other player has taken their turn.
Finally if you want to do a push from the backend to the browser you will need to investigate django channels which allows you to setup a websocket connection from the backend to the front end. This will allow you to update your UI as new data is available.
For a new user you might want to progress through the options in the order that has been outlined just to build your experience.

Django: Using django.contrib.auth for SAAS ( Users, permissions, etc. )

I'm making a SAAS and I've been asking a slew of questions on here related to the Auth system built in. I'm having trouble understanding the "why" and "how". Primarily I don't understand how it fits in with my SAAS.
I (do) know the following:
You can do this: http://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users
There are many reasons to use the built in auth system (like security) instead of rolling your own
I (don't) know the following:
class MyUserProfile(models.Model):
"""
Administrator for an Account. Can edit tickets and other stuff.
"""
user = AutoOneToOneField(User, primary_key=True)
account = models.ForeignKey(Account)
dogs_name = models.CharField(max_length=255)
In the previous example, account is just what you'd expect; an entity that's paying to use my software. user is my main concern. Somebody goes to a page and creates a UserProfile with a username and password, etc. When they do this, where does the related User get created? Do I need to create it in my view manually based on the request.POST['username'], etc, and then do
myuserprof = MyUserProfile.create(user=foo_user_just_created, account=foo_account, dogs_name='Spot')
I don't know why but for some reason I feel like I'm missing something. This idea of asking somebody to sign up for an account, and then create a MyUserProfile with a form that asks for the password, username, email, et al, and then in my view creating 2 different objects (MyUserProfile and User) with different parts of the form data. I mean I shouldn't have a User form right? Like I said, I feel like I'm either skipping a step or I'm in the wrong paradigm. I'm not new to Django, but for some reason I have trouble with things that I didn't build (I think it might be a mental problem for real at this point).
Maybe there is a good example of this sort of thing being done on some open source project.
Update: Oops, forgot to mention that in the code above I tried to use AutoOneToOneField from django-annoying, but I have no idea where all the User's attributes get set or how to decide which User object to attach to it. This stuff is driving me crazy.
Also, do I need to use the sites app to do this stuff, and finally does a "super user" have all permissions to everything (I don't want people from Account "Acme" to access account "Microshaft" objects)? Or do they just have all permissions to all views?
Somebody goes to a page and creates a UserProfile with a username and password, etc.
UserProfile doesn't have an username or password field. So it should be somebody goes to a page and create an User. Then, it creates an UserProfile associated to that newly created User.
The question is, how and when do you want this UserProfile instance to be created?
Automatically, whenever a new User is created : use signals, as described in the docs
Automatically, whenever the profile is accessed from an user instance : use AutoOneToOneField, and access the profile using user.userprofile instead of user.get_profile()
Manually. But don't forget an user might have no UserProfile associated yet, so user.get_profile() might raise a DoesNotExist exception.
When they do this, where does the related User get created?
It doesn't. You have to create it explicitely.
This idea of asking somebody to sign up for an account, and then create a MyUserProfile with a form that asks for the password, username, email, et al, and then in my view creating 2 different objects (MyUserProfile and User) with different parts of the form data. I mean I shouldn't have a User form right?
Why not? You want here to create an User and his associated profile in one go, right? You could eventually use directly the POST data, or use a Form to access to the fields, or even better, use 2 ModelForm (one for User, one for UserProfile) that you will process in the same view (maybe this question can help?)
Maybe there is a good example of this sort of thing being done on some open source project.
I suggest you check out django-registration and django-profiles.
Note
You have another way of adding information to an User object, by extending the model itsel. It will allow you to put your extra fields directly in the user model and might be easier for you to understand and use.
I won't dive into details here, have a look at that tutorial for more informations.
Other questions
I tried to use AutoOneToOneField from django-annoying, but I have no idea where all the User's attributes get set or how to decide which User object to attach to it. This stuff is driving me crazy
See above on how to use it. If you feel uncomfortable with it, the best is to follow the documentation, which recommend using a ForeignKey with unique=True in user profiles.
Also, do I need to use the sites app to do this stuff
From the site framework docs : Use it if your single Django installation powers more than one site and you need to differentiate between those sites in some way.
and finally does a "super user" have all permissions to everything (I don't want people from Account "Acme" to access account "Microshaft" objects)?
Again, from the docs, Designates that this user has all permissions without explicitly assigning them. That means that everywhere Django is using the built-in permission system (e.g. default administration pages), a super-user will be authorized.
In views you're writing yourself, or if you tweak some ModelAdmin, it's up to you to decide how you are going to check permissions.

Categories

Resources