Filter users by user group in tastypie - tastypie

This is my user resource class
class UserResource(ModelResource):
class Meta:
queryset = User.objects.all()
allowed_methods = ['get', 'post', 'put', 'patch']
resource_name = 'user'
excludes = ['password']
#authentication = SessionAuthentication()
#authorization = DjangoAuthorization()
authorization = Authorization()
authentication = Authentication()
always_return_data = True
filtering = {
'id': ALL,
'username': ALL,
'groups': ALL_WITH_RELATIONS
}
I want to filter user by their group names.
Like /api/v1/user/?format=json&groups__name=group_name
The above format is not working. How can i filter it in the get request?

You have to add relational fields from model that you are going to use to your resource. In first place you have to create Model resource for Group model. Then create To Many field in UserResource linked to GroupResource.
Something like this:
class GroupResource(ModelResource):
class Meta:
queryset = Group.objects.all()
resource_name = 'group'
authorization = Authorization()
authentication = Authentication()
always_return_data = True
filtering = {
'id': ALL,
'name': ALL,
}
class UserResource(ModelResource):
groups = fields.ToManyField(GroupResource, 'groups',
blank=True)
class Meta:
queryset = User.objects.all()
allowed_methods = ['get', 'post', 'put', 'patch']
resource_name = 'user'
excludes = ['password']
#authentication = SessionAuthentication()
#authorization = DjangoAuthorization()
authorization = Authorization()
authentication = Authentication()
always_return_data = True
filtering = {
'id': ALL,
'username': ALL,
'groups': ALL_WITH_RELATIONS
}
The reason of that is Tastypie has to know relational object authorization, authentication, resource_name and rest bunch of settings that can't populate itself.

Related

How can I save url and local images?

I'm working on a project that uses the Spotify API. I get all the top tracks and top artists from users. I save the information into my database, the image that I get from Spotify is a URL image. Like this https://i.scdn.co/image/ab67616d0000b27300d5163a674cf57fe79866a6
In my CMS I want to be able to change the image of an artist or track. For this, I copied the code from the docs https://backpackforlaravel.com/docs/4.1/crud-fields#image-1 "public function setImageAttribute($value) and put this in my model. Everything is working fine for this part, I can upload a new image and it saves into my public folder and gets displayed in my table.
The problem that I have is that when a new user logs in and the artist/track data needs to be saved in the database it goes through this setImageAttribute($value) in the model and doesn't add the URL into the database column.
Is there a way that I can add the URL image without going through the setImageAttribute function in the model?
The controller:
//get Top Artists
$client = new Client([]);
$topartists = $client->get('https://api.spotify.com/v1/me/top/artists?time_range=medium_term&limit=25&offset=5', [
'headers' => [
'Authorization' => 'Bearer ' . $token,
],
]);
$listtopartists = json_decode($topartists->getBody(), true);
$p = 25;
foreach ($listtopartists['items'] as $topartist) {
$artist = TopArtist::where('artist_id', $topartist['id'])->first();
$artist_genre = json_encode($topartist['genres']);
if ($artist === null) {
$new_artist = TopArtist::create([
'artist_id' => $topartist['id'],
'name' => $topartist['name'],
'genres' => $artist_genre,
'users_popularity' => $p,
'popularity' => $topartist['popularity'],
'image' => $topartist['images'][0]['url'],
'url' => $topartist['external_urls']['spotify'],
]);
$spotify_user->topArtists()->attach($new_artist->id);
} else {
$exists = $spotify_user->topArtists()->where('spotify_user_id', $spotify_user->id)->where('top_artist_id', $artist->id)->get();
if ($exists->isEmpty()) {
$spotify_user->topArtists()->attach($artist->id);
}
}
$p--;
}
The Model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
class TopArtist extends Model
{
use \Backpack\CRUD\app\Models\Traits\CrudTrait;
use HasFactory;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'artist_id',
'name',
'popularity',
'users_popularity',
'url',
'image',
'genres',
'status',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'id' => 'integer',
'status' => 'boolean',
];
public function setImageAttribute($value)
{
$attribute_name = "image";
// or use your own disk, defined in config/filesystems.php
$disk = config('backpack.base.root_disk_name');
// destination path relative to the disk above
$destination_path = "public/storage/artists";
// if the image was erased
if ($value==null) {
// delete the image from disk
\Storage::disk($disk)->delete($this->{$attribute_name});
// set null in the database column
$this->attributes[$attribute_name] = null;
}
// if a base64 was sent, store it in the db
if (Str::startsWith($value, 'data:image'))
{
$image = \Image::make($value)->encode('jpg', 90);
$filename = md5($value.time()).'.jpg';
\Storage::disk($disk)->put($destination_path.'/'.$filename, $image->stream());
\Storage::disk($disk)->delete($this->{$attribute_name});
$public_destination_path = Str::replaceFirst('public/', '', $destination_path);
$this->attributes[$attribute_name] = $public_destination_path.'/'.$filename;
}
}
public function spotifyUsers()
{
return $this->belongsToMany(\App\Models\SpotifyUser::class);
}
}
I fixed it, I had to add an else statement after
if (Str::startsWith($value, 'data:image'))
in the model where I set $this->attributes[$attribute_name] = $value;.

Perl's OpenAPI::Client - how to pass additionalProperties in OpenAPI GET query request?

I'm trying to pass filter variables in a GET request to an OpenAPI route with this specification:
- in: query
name: params
schema:
type: object
additionalProperties:
type: string
style: form
explode: true
I've tried various different ways of passing the data at request time:
my $client = OpenAPI::Client->new(...);
my $tx = $client->findApps({
params => { 'id' => '1' }
});
my $tx = $client->findApps({ 'id' => '1' });
What is the correct way to do this?

How to set 'Author' for a node type on a custom form?

I have following code...
I have a node type called MY_NODE_TYPE.
I have set up a cusdtom URL for my node type: 'node/%/bla'). At this URL my 'default author' field is set to 'Anonymous' when it should be admin (uid 1).
I'd like to know where I should set uid to be 1 if following code does not work. (How can I make this code work?)
function bla_menu() {
$items['node/%/bla'] = array(
'title' => t('Bla'),
'page callback' => 'bla_callback',
);
}
function bla_callback () {
module_load_include('inc', 'node', 'node.pages');
$new_node = new stdClass;
$new_node->type = 'bla';
node_object_prepare($new_node);
$new_node->language = LANGUAGE_NONE;
$new_node->uid = 1;//This is wehre I set uid to be one and is not effective
return drupal_get_form('MY_NODE_TYPE_form', $new_node);
}
You should implement hook_node_presave to set the values you need to change there.
Code sample:
function MODULE_node_presave($node) {
if($node->type === 'MY_NODE_TYPE')
$node->uid = 1;
}

Flask Admin doesn't show all fields

I have model like this:
class User(db.Model):
__tablename__ = 'users'
__table_args__ = {'mysql_engine' : 'InnoDB', 'mysql_charset' : 'utf8'}
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
email = db.Column(db.String(120), unique=True)
_password = db.Column('password', db.String(80))
def __init__(self, username = None, email = None, password = None):
self.username = username
self.email = email
self._set_password(password)
def _set_password(self, password):
self._password = generate_password_hash(password)
def _get_password(self):
return self._password
def check_password(self, password):
return check_password_hash(self._password, password)
password = db.synonym("_password", descriptor=property(_get_password, _set_password))
def __repr__(self):
return '<User %r>' % self.username
I have ModelView:
class UserAdmin(sqlamodel.ModelView):
searchable_columns = ('username', 'email')
excluded_list_columns = ['password']
list_columns = ('username', 'email')
form_columns = ('username', 'email', 'password')
But no matter what i do, flask admin didn't show password field when i'm editing user info. Is there any way ? Even just to edit hash code.
UPDATE: https://github.com/mrjoes/flask-admin/issues/78
Reason why it did not work - Flask-Admin was not able to figure out what to do with SynonymProperty, so it failed to generate form field.
There's a way you can have it working right now:
class UserAdmin(sqlamodel.ModelView):
searchable_columns = ('username', 'email')
excluded_list_columns = ['password']
list_columns = ('username', 'email')
form_columns = ('username', 'email')
def scaffold_form(self):
form_class = super(UserAdmin, self).scaffold_form()
form_class.password = wtf.TextField('Password')
return form_class
I pushed simple fix which adds support for the SynonymProperty, so it will work even without form customization. Unfortunately, I'm in process of adding MongoDB backend, so I won't be able to release new version any time soon.
Just in case, SynonymProperty was superseded by hybrid properties in SQLAlchemy 0.7 and onward, which should be supported by the Flask-Admin.
Much better:
from wtforms.fields import PasswordField
class UserAdmin(sqlamodel.ModelView):
searchable_columns = ('username', 'email')
excluded_list_columns = ['password']
form_overrides = dict(password=PasswordField)

How do I check if a given user ID has authenticated my app?

I'm using the Facebook Graph API and want to check if a user has authenticated my Facebook app by user ID. How do I do this?
You use:
SELECT is_app_user FROM user WHERE uid=USER_ID
This should return:
[
{
"is_app_user": true
}
]
If the user has logged in to your application.
Expanding on ifaour's answer, in PHP this query would look something like this:
<?php
$facebook = new Facebook(
'appID' => YOUR_APP_ID,
'secret' => YOUR_APP_SECRET
);
$result = $facebook->api(array(
'method' => 'fql.query',
'query' => "SELECT is_app_user FROM user WHERE uid=$user_id"
));
$is_installed = $result[0]['is_app_user'];
Here you can batch multiple requests together and avoid using FQL.
Assuming you have already logged into facebook and set the access token to the application access token, you can do this:
$batch = array();
foreach($friendArray AS $friend) {
$batch[] = array(
'method' => 'GET',
'relative_url' => '/' . $friend . '?fields=installed'
);
}
FB()->useApplicationAccessToken();
$batchResponse = FB()->facebook()->api('?batch='.json_encode($batch), 'POST');
Then you can process the batch response with code like this:
$installedUsers = array();
$notInstalledUsers = array();
foreach ($batchResponse AS $response) {
$body = json_decode($response['body'], true);
if (!isset($body['id']))
continue;
$id = $body['id'];
if (isset($body['installed']))
$installedUsers[] = $id;
else
$notInstalledUsers[] = $id;
}