Django guardian user.has_perm false for existing data - django

I was trying to give permission using Django guardian. when I try to give permission for existing data its show me a false message but when I create a new object its show me true. what I'm doing wrong?
My code :
>>>from django.contrib.auth.models import User
>>>from print.models import *
>>>from guardian.shortcuts import assign_perm
>>>user = User.objects.create(username='tanvir',password='antu')
>>>excel = ExcelData.objects.all()
>>>assign_perm('delete_exceldata', user, excel)
>>>user.has_perm('delete_exceldata', excel)
>>>False
But If I do
>>>from django.contrib.auth.models import User
>>>from print.models import *
>>>from guardian.shortcuts import assign_perm
>>>user = User.objects.create(username='tanvir',password='antu')
>>>excel = ExcelData.objects.create(order_number='01245632145214')
>>>assign_perm('delete_exceldata', user, excel)
>>>user.has_perm('delete_exceldata', excel)
>>>True

excel = ExcelData.objects.all()
will give you a queryset and
excel=ExcelData.objects.create(order_number='1245632145214')
will give you an object..
You can only assign permission to an object
if you want to assign permission for a queryset do it inside a loop
user = User.objects.create(username='tanvir',password='antu')
excel = ExcelData.objects.all()
for obj in excel:
assign_perm('delete_exceldata', user, obj)
user.has_perm('delete_exceldata', obj) # this will give you status for each obj

Related

Graphene-Django: In schema combine Query-objects (only takes first argument)

I am trying to combine multiple Query schemas located in different apps in Django 2.1. Using graphene-django 2.2 (have tried 2.1 with same problem). Python 3.7.
The Query class only registers the first variable. As an example shop.schema.Query.
import graphene
import graphql_jwt
from django.conf import settings
import about.schema
import shop.schema
import landingpage.schema
class Query(about.schema.Query, shop.schema.Query, landingpage.schema.Query, graphene.ObjectType):
pass
class Mutation(shop.schema.Mutation, graphene.ObjectType):
token_auth = graphql_jwt.ObtainJSONWebToken.Field()
verify_token = graphql_jwt.Verify.Field()
refresh_token = graphql_jwt.Refresh.Field()
schema = graphene.Schema(query=Query, mutation=Mutation)
Why is it like this? Have something changed with classes in python 3.7? The graphene tutorial says this will inherit for multiple...
class Query(cookbook.ingredients.schema.Query, graphene.ObjectType):
# This class will inherit from multiple Queries
# as we begin to add more apps to our project
pass
schema = graphene.Schema(query=Query)
I am exporting my schema to schema.json for using it with react relay. I do find my object "collection" Query schema from landingpage(the 3. variable). Relay returns:
ERROR: GraphQLParser: Unknown field collection on type Viewer.
Source: document AppQuery file: containers/App/index.js.
Is it a problem with Relay reading my schema.json?
I managed to solve it shortly after writing this. My problem was that I had a Viewer object in every app. Because I find it useful to have a viewer-graphql-root, like this:
graphql'
viewer {
collection {
somestuff
}
}
'
I moved the Viewer object up to the root schema.py like this:
class Viewer(about.schema.Query, landingpage.schema.Query, shop.schema.Query, graphene.ObjectType):
class Meta:
interfaces = [relay.Node, ]
class Query(graphene.ObjectType):
viewer = graphene.Field(Viewer)
def resolve_viewer(self, info, **kwargs):
return Viewer()
class Mutation(shop.schema.Mutation, graphene.ObjectType):
token_auth = graphql_jwt.ObtainJSONWebToken.Field()
verify_token = graphql_jwt.Verify.Field()
refresh_token = graphql_jwt.Refresh.Field()
schema = graphene.Schema(query=Query, mutation=Mutation)
In setting.py add a new file as schema.py
Combine your Queries and Mutations in schema.py as follows:
import graphene
import about.schema as about
import shop.schema as projects
import landingpage.schema as projects
then add:
class Query(about.schema.Query, shop.schema.Query, landingpage.schema.Query, graphene.ObjectType):
pass
class Mutation(about.schema.Mutation, shop.schema.Mutation, landingpage.schema.Mutation, graphene.ObjectType):
pass
schema = graphene.Schema(query=Query, mutation=Mutation)
Configure your combined schema in settings.py as follows:
GRAPHENE = {
"SCHEMA": "core.schema.schema",
}

Remove old permissions in django

In my Django site there are some permissions entries linked to applications that I've removed. For example I have permissions entries linked to "Dashboard" and "Jet" applications. How can you remove them?
Permissions have foreign keys to content types under the hood, so removing the content types for the models that no longer exist will also remove the permissions for those models.
Fortunately, Django also provides a manage.py command to remove old content types: remove_stale_contenttypes. Running that command will list the content types that no longer exist and the related objects (including permissions) that will be deleted, allowing you to review the changes and approve them.
$ manage.py remove_stale_contenttypes
Some content types in your database are stale and can be deleted.
Any objects that depend on these content types will also be deleted.
The content types and dependent objects that would be deleted are:
- Content type for stale_app.removed_model
- 4 auth.Permission object(s)
This list doesn't include any cascade deletions to data outside of Django's
models (uncommon).
Are you sure you want to delete these content types?
If you're unsure, answer 'no'.
Type 'yes' to continue, or 'no' to cancel:
To start, make an empty migration file:
python manage.py makemigrations --empty yourappname
Change the migration (this is an example, adjust to your needs):
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations
def add_permissions(apps, schema_editor):
pass
def remove_permissions(apps, schema_editor):
"""Reverse the above additions of permissions."""
ContentType = apps.get_model('contenttypes.ContentType')
Permission = apps.get_model('auth.Permission')
content_type = ContentType.objects.get(
model='somemodel',
app_label='yourappname',
)
# This cascades to Group
Permission.objects.filter(
content_type=content_type,
codename__in=('add_somemodel', 'change_somemodel', 'delete_somemodel'),
).delete()
class Migration(migrations.Migration):
dependencies = [
('yourappname', '0001_initial'),
]
operations = [
migrations.RunPython(remove_permissions, add_permissions),
]
I did it this way:
import re
for perm in Permission.objects.all():
if re.match( r".+modelname.+permissionname.+",str(perm)):
print(perm)
perm.delete()
If you have custom or model based (default) permissions you wish to remove you could write a command like this to accomplish this task:
from django.conf import settings
from django.contrib.auth.models import Permission
from django.core.management.base import BaseCommand
import django.apps
class Command(BaseCommand):
help = 'Remove custom permissions that are no longer in models'
def handle(self, *args, **options):
# get the db name needed for removal...
database_name = input('Database Name: ')
default_perm_names = list()
# are real perms in db, may not be accurate
db_custom_perm_names = list()
# will be used to ensure they are correct.
meta_custom_perm_names = list()
default_and_custom_perms = list()
for model in django.apps.apps.get_models():
# add to models found to fix perms from removed models
app_label = model._meta.app_label
lower_model_name = model._meta.model_name
all_model_permissions = Permission.objects.using(database_name).filter(content_type__app_label=app_label, content_type__model=lower_model_name)
default_and_custom_perms.extend([x for x in all_model_permissions])
# get the custom meta permissions, these should be in the meta of the class
# will be a list or tuple or list, [0=codename, 1=name]
meta_permissions = model._meta.permissions
if meta_permissions:
for perm in all_model_permissions:
# will be the model name from the content type, this is how django makes default perms
# we are trying to remove them so now we can figure out which ones are default by provided name
model_name_lower = perm.content_type.name
# default_perms = ['add', 'change', 'view', 'delete', 'undelete']
# append them to the list of default names
default_perm_names.append(f'Can add {model_name_lower}')
default_perm_names.append(f'Can change {model_name_lower}')
default_perm_names.append(f'Can view {model_name_lower}')
default_perm_names.append(f'Can delete {model_name_lower}')
default_perm_names.append(f'Can undelete {model_name_lower}')
# will mean this is a custom perm...so add it
if not perm.name in default_perm_names:
db_custom_perm_names.append(perm.name)
# the perms to ensure are correct...
for model_perm in meta_permissions:
# get the meta perm, will be a list or tuple or list, [0=codename, 1=name]
custom_perm = Permission.objects.using(database_name).get(codename=model_perm[0], name=model_perm[1])
meta_custom_perm_names.append(custom_perm.name)
perms_to_remove = [perm for perm in db_custom_perm_names if perm not in meta_custom_perm_names]
if not perms_to_remove:
print('There are no stale custom permissions to remove.')
# print(perms_to_remove)
# now remove the custom permissions that were removed from the model
for actual_permission_to_remove in Permission.objects.using(database_name).filter(name__in=perms_to_remove):
# print(actual_permission_to_remove)
actual_permission_to_remove.delete(using=database_name)
print(actual_permission_to_remove, '...deleted')
for perm in [x for x in Permission.objects.using(database_name)]:
# loop all perms...if it is not in the model perms it does not exist...
if perm.content_type.model not in [x.content_type.model for x in default_and_custom_perms]:
perm.delete(using=database_name)
print(perm, 'regular permission...deleted')
If you also wish to ensure that the default permissions are added from Django you can add this snippet in the command:
from django.apps import apps
from django.contrib.auth.management import create_permissions
from apps.client.models import ClientInformation
# add all permissions the django way
# get the db name needed from settings.py
database_name = 'default' # or whatever DB you are looking for
print(f'adding all permissions if not there to {database_name}')
for app_config in apps.get_app_configs():
# print(app_config)
app_config.models_module = True
create_permissions(app_config, using=database_name)
app_config.models_module = None
Then call via python manage.py fix_permissions if you name your command file fix_permissions.py
I've reworked #ViaTech's code to use Django's contrib.auth.management._get_all_permissions() functions which makes it more straight forward:
from typing import List, Set, Tuple
import django.apps
# noinspection PyProtectedMember
from django.contrib.auth.management import _get_all_permissions
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from django.core.management.base import BaseCommand
from django.db import DEFAULT_DB_ALIAS
class Command(BaseCommand):
help = "Remove custom permissions that are no longer defined in models"
def add_arguments(self, parser):
parser.add_argument(
"--database",
default=DEFAULT_DB_ALIAS,
help=f'Specifies the database to use. Default is "{DEFAULT_DB_ALIAS}".',
)
parser.add_argument(
"--dry",
action="store_true",
help="Do a dry run not actually deleting any permissions",
)
def handle(self, *args, **options) -> str:
using = options["database"]
# This will hold the permissions that models have defined,
# i.e. default permissions plus additional custom permissions:
# (content_type.pk, codename)
defined_perms: List[Tuple[int, str]] = []
for model in django.apps.apps.get_models():
ctype = ContentType.objects.db_manager(using).get_for_model(
model, for_concrete_model=False
)
# noinspection PyProtectedMember
for (codename, _) in _get_all_permissions(model._meta):
defined_perms.append((ctype.id, codename))
# All permissions in current database (including stale ones)
all_perms = Permission.objects.using(using).all()
stale_perm_pks: Set[int] = set()
for perm in all_perms:
if (perm.content_type.pk, perm.codename) not in defined_perms:
stale_perm_pks.add(perm.pk)
self.stdout.write(f"Delete permission: {perm}")
# Delete all stale permissions
if options["dry"]:
result = f"DRY RUN: {len(stale_perm_pks)} stale permissions NOT deleted"
else:
if stale_perm_pks:
Permission.objects.filter(pk__in=stale_perm_pks).delete()
result = f"{len(stale_perm_pks)} stale permissions deleted"
return result

Google app engine: object has no attribute ToMessage

I am trying to implement a service which checks if the logged in user is on a datastore, if yes returns True, if not returns False.
Here is the code I am using:
import endpoints
from google.appengine.ext import ndb
from protorpc import remote
from protorpc import messages
from endpoints_proto_datastore.ndb import EndpointsModel
from google.appengine.api import users
class AuthRes(messages.Message):
message = messages.StringField(1)
class UserModel(EndpointsModel):
user = ndb.UserProperty()
#endpoints.api(name='myapi', version='v1', description='My Little API')
class MyApi(remote.Service):
#UserModel.method(path='myuser', http_method='GET', name='myuser.check')
def UserCheck(self, cls):
user = users.get_current_user()
if user:
myuser = cls.query().filter(cls.user.user_id() == user.user_id()).get()
if not myuser:
return AuthRes(message="False")
else:
return AuthRes(message="True")
else:
return AuthRes(message="False")
application = endpoints.api_server([MyApi], restricted=False)
I always get 'AuthRes' object has no attribute 'ToMessage'
I believe instead of this:
#UserModel.method(path='myuser', http_method='GET', name='myuser.check')
you want this:
from protorpc import message_types # add at the top
#endpoints.method(message_types.VoidMessage, AuthRes, path='myuser', http_method='GET', name='myuser.check')

How to create 2 pages from reportlab using one PageTemplate?

Hi all reportlab master,
I've search the web and also here in stackoverflow but can't find a similar situation on my problem I'm trying to solve during this Holiday vacation.
In django admin, I'm trying to create an action to view my database to a specific format. If I select one record I can view the report in one page pdf. Which is fine. In case the user try to more record that's where the problem start. For example I select multiple record, I can view the report but all content is still in one page pdf.
Is there a way to show a record per page in pdf? All reportlab master jedi, Please help me how to do this the right way.
Here's my code on what I did.
from django.contrib import admin
from models import LatestRsl
from io import BytesIO
from reportlab.pdfgen import canvas
from django.http import HttpResponse
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
from reportlab.lib.units import inch
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.platypus import BaseDocTemplate, PageTemplate, Paragraph, Frame
from reportlab.lib.pagesizes import letter
def go(modeladmin, request, queryset):
response = HttpResponse(mimetype='application/pdf')
response['Content-Disposition'] = 'filename = testframe.pdf'
buffer = StringIO()
c = canvas.Canvas(buffer)
doc = BaseDocTemplate(buffer, showBoundary=1, leftMargin= 0.1*inch, rightMargin= 0.1*inch,
topMargin= 0.1*inch, bottomMargin= 0.1*inch)
signfr = Frame(5.1*inch, 1.2*inch, 2.8*inch, 0.44*inch, showBoundary=1)
modelfr = Frame(3.6*inch, 4.6*inch, 2.8*inch, 0.44*inch, showBoundary=1)
doc.addPageTemplates([PageTemplate(id= 'rsl_frame', frames=[signfr, modelfr]),
PageTemplate(id= 'rsl_frame2', frames=[signfr, modelfr])])
story = []
styles=getSampleStyleSheet()
styles.add(ParagraphStyle(name='Verdana9', fontName= 'Verdana', fontSize= 9))
styles.add(ParagraphStyle(name='VerdanaB10', fontName= 'VerdanaB', fontSize= 10))
for obj in queryset:
#1st frame
model = Paragraph(obj.make,styles["Verdana9"])
story.append(model)
modelfr.addFromList(story,c)
#2nd frame
signatory = Paragraph(obj.signatory,styles["VerdanaB10"])
story.append(signatory)
signfr.addFromList(story,c)
doc.build(story)
c.showPage()
c.save()
pdf = buffer.getvalue()
buffer.close()
response.write(pdf)
return response
Assuming your queryset variable contains all the records you need, you could insert a PageBreak object. Just add from reportlab.platypus import PageBreak to the top of your file, then append a PageBreak object to your document's elements.
If you want to change the template for each page, you can also append a NextPageTemplate and pass the id of your PageTemplate. You'll need to add from reportlab.platypus import NextPageTemplate to the top of your file as well.
for obj in queryset:
#1st frame
model = Paragraph(obj.make,styles["Verdana9"])
story.append(model)
modelfr.addFromList(story,c)
#2nd frame
signatory = Paragraph(obj.signatory,styles["VerdanaB10"])
story.append(signatory)
signfr.addFromList(story,c)
# Force the report to use a different PageTemplate on the next page
story.append(NextPageTemplate('rsl_frame2'))
# Start a new page for the next object in the query
story.append(PageBreak())
You could move the PageBreak wherever you need it, but it's a simple "function" flowable. NextPageTemplate can take the id of any valid PageTemplate object that you've added via addPageTemplates.

How to get logged in user's uid from session in Django?

I have implemented a registration/login/authentication system using this Django guide.
But, how would I access a user's information from my views so I can send the user's information to a template file?
I want to be able to access a user's ID so I can submit a form with the user's ID attached to the form.
In case anyone wants to actually extract a user ID from an actual Session object (for whatever reason - I did!), here's how:
from django.contrib.sessions.models import Session
from django.contrib.auth.models import User
session_key = '8cae76c505f15432b48c8292a7dd0e54'
session = Session.objects.get(session_key=session_key)
session_data = session.get_decoded()
print session_data
uid = session_data.get('_auth_user_id')
user = User.objects.get(id=uid)
Credit should go to Scott Barnham
There is a django.contrib.auth.models.User object attached to the request; you can access it in a view via request.user. You must have the auth middleware installed, though.
This:
def view(request):
if request.user.is_authenticated:
user = request.user
print(user)
# do something with user
An even easier way to do this is to install django-extensions and run the management command print_user_for_session.
And this is how they do it:
https://github.com/django-extensions/django-extensions/blob/master/django_extensions/management/commands/print_user_for_session.py
In case hwjp solution doesn't work for you ("Data is corrupted"), here is another solution:
import base64
import hashlib
import hmac
import json
def session_utoken(msg, secret_key, class_name='SessionStore'):
key_salt = "django.contrib.sessions" + class_name
sha1 = hashlib.sha1((key_salt + secret_key).encode('utf-8')).digest()
utoken = hmac.new(sha1, msg=msg, digestmod=hashlib.sha1).hexdigest()
return utoken
def decode(session_data, secret_key, class_name='SessionStore'):
encoded_data = base64.b64decode(session_data)
utoken, pickled = encoded_data.split(b':', 1)
expected_utoken = session_utoken(pickled, secret_key, class_name)
if utoken.decode() != expected_utoken:
raise BaseException('Session data corrupted "%s" != "%s"',
utoken.decode(),
expected_utoken)
return json.loads(pickled.decode('utf-8'))
s = Session.objects.get(session_key=session_key)
decode(s.session_data, 'YOUR_SECRET_KEY'))
credit to: http://joelinoff.com/blog/?p=920