deprecated all old vue stuff and working on tests

This commit is contained in:
vabene1111
2022-06-07 20:08:32 +02:00
parent 37f0f7a0b7
commit e368488933
22 changed files with 1803 additions and 12510 deletions

View File

@ -14,6 +14,12 @@ class ScopeMiddleware:
def __call__(self, request):
prefix = settings.JS_REVERSE_SCRIPT_PREFIX or ''
# need to disable scopes for writing requests into userpref and enable for loading ?
# if request.path.startswith(prefix + '/api/user-preference/'):
# with scopes_disabled():
# return self.get_response(request)
if request.user.is_authenticated:
if request.path.startswith(prefix + '/admin/'):

View File

@ -10,6 +10,7 @@ from django.db.models import Avg, Q, QuerySet, Sum
from django.http import BadHeaderError
from django.urls import reverse
from django.utils import timezone
from django_scopes import scopes_disabled
from drf_writable_nested import UniqueFieldsMixin, WritableNestedModelSerializer
from rest_framework import serializers
from rest_framework.exceptions import NotFound, ValidationError
@ -242,12 +243,12 @@ class UserPreferenceSerializer(WritableNestedModelSerializer):
space = getattr(self.context.get('request', None), 'space', None)
return Food.objects.filter(depth__gt=0, space=space).exists()
def update(self, instance, validated_data):
with scopes_disabled():
return super().update(instance, validated_data)
def create(self, validated_data):
if not validated_data.get('user', None):
raise ValidationError(_('A user is required'))
if (validated_data['user'] != self.context['request'].user):
raise NotFound()
return super().create(validated_data)
raise ValidationError('Cannot create using this endpoint')
class Meta:
model = UserPreference

View File

@ -7,7 +7,7 @@ from django.contrib.postgres.search import SearchVector
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.utils import translation
from django_scopes import scope
from django_scopes import scope, scopes_disabled
from cookbook.helper.shopping_helper import RecipeShoppingEditor
from cookbook.managers import DICTIONARY
@ -34,9 +34,9 @@ def skip_signal(signal_func):
@receiver(post_save, sender=User)
@skip_signal
def update_recipe_search_vector(sender, instance=None, created=False, **kwargs):
def create_user_preference(sender, instance=None, created=False, **kwargs):
if created:
with scopes_disabled():
UserPreference.objects.get_or_create(user=instance)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,146 +0,0 @@
/**
* Vue Cookies v1.7.4
* https://github.com/cmp-cc/vue-cookies
*
* Copyright 2016, cmp-cc
* Released under the MIT license
*/
(function () {
var defaultConfig = {
expires: '1d',
path: '; path=/',
domain: '',
secure: '',
sameSite: '; SameSite=Lax'
};
var VueCookies = {
// install of Vue
install: function (Vue) {
Vue.prototype.$cookies = this;
Vue.$cookies = this;
},
config: function (expireTimes, path, domain, secure, sameSite) {
defaultConfig.expires = expireTimes ? expireTimes : '1d';
defaultConfig.path = path ? '; path=' + path : '; path=/';
defaultConfig.domain = domain ? '; domain=' + domain : '';
defaultConfig.secure = secure ? '; Secure' : '';
defaultConfig.sameSite = sameSite ? '; SameSite=' + sameSite : '; SameSite=Lax';
},
get: function (key) {
var value = decodeURIComponent(document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + encodeURIComponent(key).replace(/[\-\.\+\*]/g, '\\$&') + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1')) || null;
if (value && value.substring(0, 1) === '{' && value.substring(value.length - 1, value.length) === '}') {
try {
value = JSON.parse(value);
} catch (e) {
return value;
}
}
return value;
},
set: function (key, value, expireTimes, path, domain, secure, sameSite) {
if (!key) {
throw new Error('Cookie name is not find in first argument.');
} else if (/^(?:expires|max\-age|path|domain|secure|SameSite)$/i.test(key)) {
throw new Error('Cookie key name illegality, Cannot be set to ["expires","max-age","path","domain","secure","SameSite"]\t current key name: ' + key);
}
// support json object
if (value && value.constructor === Object) {
value = JSON.stringify(value);
}
var _expires = '';
expireTimes = expireTimes == undefined ? defaultConfig.expires : expireTimes;
if (expireTimes && expireTimes != 0) {
switch (expireTimes.constructor) {
case Number:
if (expireTimes === Infinity || expireTimes === -1) _expires = '; expires=Fri, 31 Dec 9999 23:59:59 GMT';
else _expires = '; max-age=' + expireTimes;
break;
case String:
if (/^(?:\d+(y|m|d|h|min|s))$/i.test(expireTimes)) {
// get capture number group
var _expireTime = expireTimes.replace(/^(\d+)(?:y|m|d|h|min|s)$/i, '$1');
// get capture type group , to lower case
switch (expireTimes.replace(/^(?:\d+)(y|m|d|h|min|s)$/i, '$1').toLowerCase()) {
// Frequency sorting
case 'm':
_expires = '; max-age=' + +_expireTime * 2592000;
break; // 60 * 60 * 24 * 30
case 'd':
_expires = '; max-age=' + +_expireTime * 86400;
break; // 60 * 60 * 24
case 'h':
_expires = '; max-age=' + +_expireTime * 3600;
break; // 60 * 60
case 'min':
_expires = '; max-age=' + +_expireTime * 60;
break; // 60
case 's':
_expires = '; max-age=' + _expireTime;
break;
case 'y':
_expires = '; max-age=' + +_expireTime * 31104000;
break; // 60 * 60 * 24 * 30 * 12
default:
new Error('unknown exception of "set operation"');
}
} else {
_expires = '; expires=' + expireTimes;
}
break;
case Date:
_expires = '; expires=' + expireTimes.toUTCString();
break;
}
}
document.cookie =
encodeURIComponent(key) + '=' + encodeURIComponent(value) +
_expires +
(domain ? '; domain=' + domain : defaultConfig.domain) +
(path ? '; path=' + path : defaultConfig.path) +
(secure == undefined ? defaultConfig.secure : secure ? '; Secure' : '') +
(sameSite == undefined ? defaultConfig.sameSite : (sameSite ? '; SameSite=' + sameSite : ''));
return this;
},
remove: function (key, path, domain) {
if (!key || !this.isKey(key)) {
return false;
}
document.cookie = encodeURIComponent(key) +
'=; expires=Thu, 01 Jan 1970 00:00:00 GMT' +
(domain ? '; domain=' + domain : defaultConfig.domain) +
(path ? '; path=' + path : defaultConfig.path) +
'; SameSite=Lax';
return this;
},
isKey: function (key) {
return (new RegExp('(?:^|;\\s*)' + encodeURIComponent(key).replace(/[\-\.\+\*]/g, '\\$&') + '\\s*\\=')).test(document.cookie);
},
keys: function () {
if (!document.cookie) return [];
var _keys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, '').split(/\s*(?:\=[^;]*)?;\s*/);
for (var _index = 0; _index < _keys.length; _index++) {
_keys[_index] = decodeURIComponent(_keys[_index]);
}
return _keys;
}
};
if (typeof exports == 'object') {
module.exports = VueCookies;
} else if (typeof define == 'function' && define.amd) {
define([], function () {
return VueCookies;
});
} else if (window.Vue) {
Vue.use(VueCookies);
}
// vue-cookies can exist independently,no dependencies library
if (typeof window !== 'undefined') {
window.$cookies = VueCookies;
}
})();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,16 +0,0 @@
{% load static %}
{% load custom_tags %}
{% is_debug as DEBUG %}
{% if DEBUG %}
<script src="{% static 'js/vue.js' %}"></script>
{% else %}
<script src="{% static 'js/vue.min.js' %}"></script>
{% endif %}
<script src="{% static 'js/vue-resource.js' %}"></script>
<script src="{% static 'js/js.cookie.min.js' %}"></script>
<link rel="stylesheet" href="{% static 'css/bootstrap-vue.min.css' %}">
<script src="{% static 'js/bootstrap-vue.min.js' %}"></script>

View File

@ -1,186 +0,0 @@
{% extends "base.html" %}
{% load django_tables2 %}
{% load crispy_forms_tags %}
{% load crispy_forms_filters %}
{% load static %}
{% load i18n %}
{%block title %} {% trans "Space Settings" %} {% endblock %}
{% block extra_head %}
{{ form.media }}
{{ space_form.media }}
{% include 'include/vue_base.html' %}
{% endblock %}
{% block content %}
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{% url 'view_space_manage' request.space.pk %}">{% trans 'Space Settings' %}</a></li>
</ol>
</nav>
<h3>
<span class="text-muted">{% trans 'Space:' %}</span> {{ request.space.name }}
<small>{% if HOSTED %} <a href="https://tandoor.dev/manage">{% trans 'Manage Subscription' %}</a>{% endif %}</small>
</h3>
<br />
<div class="row">
<div class="col-md-6">
<div class="card">
<div class="card-header">{% trans 'Number of objects' %}</div>
<ul class="list-group list-group-flush">
<li class="list-group-item">
{% trans 'Recipes' %} :
<span class="badge badge-pill badge-info"
>{{ counts.recipes }} / {% if request.space.max_recipes > 0 %} {{ request.space.max_recipes }}{% else %}∞{% endif %}</span
>
</li>
<li class="list-group-item">
{% trans 'Keywords' %} : <span class="badge badge-pill badge-info">{{ counts.keywords }}</span>
</li>
<li class="list-group-item">
{% trans 'Units' %} : <span class="badge badge-pill badge-info">{{ counts.units }}</span>
</li>
<li class="list-group-item">
{% trans 'Ingredients' %} :
<span class="badge badge-pill badge-info">{{ counts.ingredients }}</span>
</li>
<li class="list-group-item">
{% trans 'Recipe Imports' %} :
<span class="badge badge-pill badge-info">{{ counts.recipe_import }}</span>
</li>
</ul>
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-header">{% trans 'Objects stats' %}</div>
<ul class="list-group list-group-flush">
<li class="list-group-item">
{% trans 'Recipes without Keywords' %} :
<span class="badge badge-pill badge-info">{{ counts.recipes_no_keyword }}</span>
</li>
<li class="list-group-item">
{% trans 'External Recipes' %} :
<span class="badge badge-pill badge-info">{{ counts.recipes_external }}</span>
</li>
<li class="list-group-item">
{% trans 'Internal Recipes' %} :
<span class="badge badge-pill badge-info">{{ counts.recipes_internal }}</span>
</li>
<li class="list-group-item">
{% trans 'Comments' %} : <span class="badge badge-pill badge-info">{{ counts.comments }}</span>
</li>
</ul>
</div>
</div>
</div>
<br />
<br />
<form action="." method="post">{% csrf_token %} {{ user_name_form|crispy }}</form>
<div class="row">
<div class="col col-md-12">
<h4>
{% trans 'Members' %}
<small class="text-muted"
>{{ space_users|length }}/{% if request.space.max_users > 0 %} {{ request.space.max_users }}{% else %}∞{% endif %}
</small>
<a class="btn btn-success float-right" href="{% url 'new_invite_link' %}"
><i class="fas fa-plus-circle"></i> {% trans 'Invite User' %}</a
>
</h4>
</div>
</div>
<br />
<div class="row">
<div class="col col-md-12">
{% if space_users %}
<table class="table table-bordered">
<tr>
<th>{% trans 'User' %}</th>
<th>{% trans 'Groups' %}</th>
<th>{% trans 'Edit' %}</th>
</tr>
{% for u in space_users %}
<tr>
<td>{{ u.user.username }}</td>
<td>{{ u.user.groups.all |join:", " }}</td>
<td>
{% if u.user != request.user %}
<div class="input-group mb-3">
<select v-model="users['{{ u.pk }}']" class="custom-select form-control" style="height: 44px">
<option value="admin">{% trans 'admin' %}</option>
<option value="user">{% trans 'user' %}</option>
<option value="guest">{% trans 'guest' %}</option>
<option value="remove">{% trans 'remove' %}</option>
</select>
<span class="input-group-append">
<a class="btn btn-warning" :href="editUserUrl({{ u.pk }}, {{ u.space.pk }})"
>{% trans 'Update' %}</a
>
</span>
</div>
{% else %} {% trans 'You cannot edit yourself.' %} {% endif %}
</td>
</tr>
{% endfor %}
</table>
{% else %}
<p>{% trans 'There are no members in your space yet!' %}</p>
{% endif %}
</div>
</div>
<div class="row">
<div class="col col-md-12">
<h4>{% trans 'Invite Links' %}</h4>
{% render_table invite_links %}
</div>
</div>
<div class="row">
<div class="col col-md-12">
<h4>{% trans 'Space Settings' %}</h4>
<form action="." method="post">
{% csrf_token %}
{{ space_form|crispy }}
<button class="btn btn-success" type="submit" name="space_form"><i
class="fas fa-save"></i> {% trans 'Save' %}</button>
</form>
</div>
</div>
<br />
<br />
<br />
{% endblock %} {% block script %}
<script type="application/javascript">
let app = new Vue({
delimiters: ['[[', ']]'],
el: '#id_base_container',
data: {
users: {
{% for u in space_users %}
'{{ u.pk }}': 'none',
{% endfor %}
}
},
mounted: function () {
},
methods: {
editUserUrl: function (user_id, space_id) {
return '{% url 'change_space_member' 1234 5678 'role' %}'.replace('1234', user_id).replace('5678', space_id).replace('role', this.users[user_id])
}
}
});
</script>
{% endblock %}

View File

@ -32,7 +32,7 @@ def sle_2(request):
u = request.getfixturevalue(params.get('user', 'u1_s1'))
user = auth.get_user(u)
count = params.get('count', 10)
return ShoppingListEntryFactory.create_batch(count, space=user.userpreference.space, created_by=user)
return ShoppingListEntryFactory.create_batch(count, space=user.userspace_set.filter(active=1).first().space, created_by=user)
@ pytest.mark.parametrize("arg", [

View File

@ -5,6 +5,8 @@ import pytest
from django.contrib import auth
from django.urls import reverse
from cookbook.models import UserSpace
LIST_URL = 'api:username-list'
DETAIL_URL = 'api:username-detail'
@ -62,8 +64,7 @@ def test_list_space(u1_s1, u2_s1, u1_s2, space_2):
assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 1
u = auth.get_user(u2_s1)
u.userpreference.space = space_2
u.userpreference.save()
UserSpace.objects.create(user=u, space=space_2)
assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 1
assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 2

View File

@ -13,16 +13,16 @@ DETAIL_URL = 'api:userpreference-detail'
def test_add(u1_s1, u2_s1):
r = u1_s1.post(reverse(LIST_URL))
assert r.status_code == 400
assert r.status_code == 405
with scopes_disabled():
UserPreference.objects.filter(user=auth.get_user(u1_s1)).delete()
r = u2_s1.post(reverse(LIST_URL), {'user': auth.get_user(u1_s1).id, 'plan_share': []}, content_type='application/json')
assert r.status_code == 404
assert r.status_code == 405
r = u1_s1.post(reverse(LIST_URL), {'user': auth.get_user(u1_s1).id, 'plan_share': []}, content_type='application/json')
assert r.status_code == 200
assert r.status_code == 405
def test_preference_list(u1_s1, u2_s1, u1_s2):
@ -51,7 +51,7 @@ def test_preference_retrieve(arg, request, u1_s1):
def test_preference_update(u1_s1, u2_s1):
# can update users preference
r = u1_s1.put(
r = u1_s1.patch(
reverse(
DETAIL_URL,
args={auth.get_user(u1_s1).id}
@ -63,8 +63,8 @@ def test_preference_update(u1_s1, u2_s1):
assert r.status_code == 200
assert response['theme'] == UserPreference.DARKLY
# cant set another users non existent pref
r = u1_s1.put(
# can't set another users non-existent pref
r = u1_s1.patch(
reverse(
DETAIL_URL,
args={auth.get_user(u2_s1).id}
@ -74,11 +74,11 @@ def test_preference_update(u1_s1, u2_s1):
)
assert r.status_code == 404
# cant set another users existent pref
# can't set another users existent pref
with scopes_disabled():
UserPreference.objects.filter(user=auth.get_user(u2_s1)).delete()
r = u1_s1.put(
r = u1_s1.patch(
reverse(
DETAIL_URL,
args={auth.get_user(u2_s1).id}

View File

@ -76,8 +76,6 @@ class UserFactory(factory.django.DjangoModelFactory):
if extracted:
for prefs in extracted:
self.userpreference[prefs] = extracted[prefs]/0 # intentionally break so it can be debugged later
self.userpreference.space = self.space
self.userpreference.save()
class Meta:
model = User

View File

@ -22,8 +22,8 @@ DATA_DIR = "cookbook/tests/other/test_data/"
@pytest.mark.parametrize("arg", [
['a_u', 302],
['g1_s1', 302],
['a_u', 403],
['g1_s1', 403],
['u1_s1', 405],
['a1_s1', 405],
])

View File

@ -355,7 +355,7 @@ class UserNameViewSet(viewsets.ReadOnlyModelViewSet):
http_method_names = ['get']
def get_queryset(self):
queryset = self.queryset.filter(userpreference__space=self.request.space)
queryset = self.queryset.filter(userspace__space=self.request.space)
try:
filter_list = self.request.query_params.get('filter_list', None)
if filter_list is not None:
@ -387,7 +387,7 @@ class UserSpaceViewSet(viewsets.ModelViewSet):
queryset = UserSpace.objects
serializer_class = UserSpaceSerializer
permission_classes = [CustomIsSpaceOwner]
http_method_names = ['get', 'patch', 'put', 'delete']
http_method_names = ['get', 'patch', 'delete']
def destroy(self, request, *args, **kwargs):
if request.space.created_by == UserSpace.objects.get(pk=kwargs['pk']).user:
@ -402,8 +402,10 @@ class UserPreferenceViewSet(viewsets.ModelViewSet):
queryset = UserPreference.objects
serializer_class = UserPreferenceSerializer
permission_classes = [CustomIsOwner, ]
http_method_names = ['get', 'patch', ]
def get_queryset(self):
with scopes_disabled(): # need to disable scopes as user preference is no longer a spaced method
return self.queryset.filter(user=self.request.user)
@ -1239,7 +1241,7 @@ def sync_all(request):
_('This feature is not yet available in the hosted version of tandoor!'))
return redirect('index')
monitors = Sync.objects.filter(active=True).filter(space=request.user.userpreference.space)
monitors = Sync.objects.filter(active=True).filter(space=request.user.userspace_set.filter(active=1).first().space)
error = False
for monitor in monitors:
@ -1302,7 +1304,7 @@ def log_cooking(request, recipe_id):
def get_plan_ical(request, from_date, to_date):
queryset = MealPlan.objects.filter(
Q(created_by=request.user) | Q(shared=request.user)
).filter(space=request.user.userpreference.space).distinct().all()
).filter(space=request.user.userspace_set.filter(active=1).first().space).distinct().all()
if from_date is not None:
queryset = queryset.filter(date__gte=from_date)