Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
a9c2214
単体テスト前コミット
ivis-akaike Jan 21, 2025
0f8ff0c
単体テスト結果反映
ivis-akaike Jan 22, 2025
0e9df26
誤記修正
ivis-akaike Jan 23, 2025
0735acc
サブリポジトリ表示機能 実装
ivis-akagawa Feb 6, 2025
3a653c0
サブリポジトリ用管理機能実装
ivis-ashino Feb 12, 2025
80af566
weko-handleに削除用のエンドポイントを追加
ivis-akaike Feb 12, 2025
bdb28a2
add alembic
ivis-ashino Feb 12, 2025
1ea9596
fix item registration report
ivis-ashino Feb 14, 2025
626826b
Alembicマイグレーション追加
ivis-akagawa Feb 17, 2025
df85f4a
インデックスツリー表示部の▼マークが展開時と折り畳み時で逆になっていたのを修正
ivis-akagawa Feb 17, 2025
5096702
thumbnail_pathがNULLだった場合に対応
ivis-akagawa Feb 17, 2025
25ae043
span要素を現行に合わせた位置に修正
ivis-akagawa Feb 17, 2025
c2923ae
アイテムファイルマウスオーバー時の日付表示情報追加
ivis-akagawa Feb 17, 2025
4193790
課題関連分を最新の状態に更新
ivis-akagawa Feb 17, 2025
6e4ccb4
fix UserView.can_delete
ivis-ashino Feb 18, 2025
d2f3ebd
コミュニティサムネイルの画像タイプ指定修正
ivis-akagawa Feb 18, 2025
e17b048
Merge pull request #460 from ivis-akagawa/w_oa_14_subrepository
ivis-akaike Feb 18, 2025
aa9fa6f
weko-index-treeのbundle実装分を更新
ivis-akagawa Feb 18, 2025
ae40f05
weko-themeのbundleが最新でなかったので更新
ivis-akagawa Feb 18, 2025
85df649
Merge pull request #461 from ivis-akaike/w_oa_14_subrepository
ivis-akaike Feb 18, 2025
3cd58dd
delete_handleの追加
ivis-akaike Feb 18, 2025
5eb94dd
fix get_repository
ivis-ashino Feb 18, 2025
346bc46
目次形式の場合のサムネイルの表示位置を調整
ivis-akagawa Feb 18, 2025
ea4a358
Merge branch 'ivis-weko3-dev:w_oa_14_subrepository' into w_oa_14_subr…
ivis-akaike Feb 18, 2025
2fbba14
Alembicのコミュニティへのcatalog_jsonカラム追加をjson→jsonb型に修正
ivis-akagawa Feb 19, 2025
6212499
Merge branch 'w_oa_14_subrepository' into w_oa_14_subrepository
ivis-ashino Feb 19, 2025
059517c
Merge pull request #466 from ivis-ashino/w_oa_14_subrepository
ivis-akaike Feb 19, 2025
59f9534
レビュー指摘事項反映
ivis-akaike Feb 19, 2025
064da64
Merge branch 'w_oa_14_subrepository' of https://github.com/ivis-akaik…
ivis-akaike Feb 19, 2025
db74055
誤記修正
ivis-akaike Feb 19, 2025
0888310
検索時アイテムの新設タブ欄にshowリストの設定が反映されるよう修正
ivis-akagawa Feb 20, 2025
a16c207
fix invenio-communities alembic head
ivis-ashino Feb 20, 2025
5afa545
fix community model
ivis-ashino Feb 20, 2025
218cb1f
Merge pull request #469 from ivis-ashino/w_oa_14_subrepository
ivis-akaike Feb 20, 2025
d8f958e
コミュニティ作成時のCNRIハンドル取得実装
ivis-akagawa Feb 21, 2025
c494230
コミュニティ削除時のハンドル削除を非同期化
ivis-akagawa Feb 21, 2025
2355df7
雑誌情報表示時のインデックスURLをエンドポイントのものに修正
ivis-akagawa Feb 21, 2025
b9a9476
テストコードコミット
ivis-akagawa Feb 21, 2025
d9799bc
index追加・削除時のハンドル操作
ivis-akaike Feb 21, 2025
71c6f3b
Merge branch 'w_oa_14_subrepository' into w_oa_14_subrepository
ivis-akagawa Feb 25, 2025
7ca4467
Merge remote-tracking branch 'upstream/w_oa_14_subrepository' into w_…
ivis-akagawa Feb 25, 2025
1695472
with context付け忘れ修正、横展開再確認済
ivis-akagawa Feb 25, 2025
eb6d6d7
Merge branch 'w_oa_14_subrepository' of https://github.com/ivis-akaga…
ivis-akagawa Feb 25, 2025
2fb66b0
「インデックスサムネイルがない場合」の条件追加
ivis-akagawa Feb 25, 2025
256e80a
著者の「and more」表示カラー変更
ivis-akagawa Feb 25, 2025
2b8f782
journalのAlembic修正
ivis-akagawa Feb 26, 2025
2993376
[invenio-accounts] add unit tests
ivis-ashino Feb 26, 2025
0b7f13d
[invenio-communities] add unit tests
ivis-ashino Feb 26, 2025
186959f
[invenio-oaiharvester] add unit tests
ivis-ashino Feb 26, 2025
26fdff0
[invenio-resourcesyncclient] add unit tests
ivis-ashino Feb 26, 2025
179ca6c
[invenio-resourcesyncserver] add unit tests
ivis-ashino Feb 26, 2025
124261d
[invenio-stats] add unit tests
ivis-ashino Feb 26, 2025
49671ea
[weko-admin] add unit tests
ivis-ashino Feb 26, 2025
a6bf2b9
[weko-authors] add unit tests
ivis-ashino Feb 26, 2025
0291c68
[weko-gridlayout] add unit tests
ivis-ashino Feb 26, 2025
b7de503
[weko-index-tree] add unit tests
ivis-ashino Feb 26, 2025
016d67f
[weko-records] add unit tests
ivis-ashino Feb 26, 2025
6e0ec35
[weko-search-ui] add unit tests
ivis-ashino Feb 26, 2025
61fdf9f
[weko-workflow] add unit tests
ivis-ashino Feb 26, 2025
d804c38
fix comadmin stats access
ivis-ashino Feb 26, 2025
8ee5081
テストコード修正
ivis-akaike Feb 26, 2025
55c80dc
単体テスト作成時に気づいたことを反映
ivis-akaike Feb 26, 2025
cbc72c7
使用していないImportを整理
ivis-akaike Feb 26, 2025
d252477
Merge pull request #465 from ivis-akagawa/w_oa_14_subrepository
ivis-akaike Feb 27, 2025
3e3afd0
Merge branch 'w_oa_14_subrepository' of https://github.com/ivis-weko3…
ivis-akaike Feb 28, 2025
26eb4e2
Merge remote-tracking branch 'upstream/w_oa_14_subrepository' into w_…
ivis-ashino Feb 28, 2025
e296252
単体テスト対応
ivis-akaike Feb 28, 2025
b0414a0
不要な処理を削除
ivis-akaike Feb 28, 2025
2acff8e
fix alembic server_default
ivis-ashino Mar 3, 2025
5b637af
Merge pull request #491 from ivis-ashino/fix_alembic_server_default
ivis-akaike Mar 3, 2025
b03593b
fix
ivis-ashino Mar 5, 2025
a639028
fix feedback mail history admin colum
ivis-ashino Mar 5, 2025
24849cc
fix
ivis-ashino Mar 5, 2025
6e28a00
Merge pull request #463 from ivis-akaike/w_oa_14_subrepository
ivis-akaike Mar 5, 2025
92dc545
Merge pull request #483 from ivis-ashino/w_oa_14_subrepository
ivis-akaike Mar 5, 2025
e59fc54
Alembic対応
ivis-akaike Mar 5, 2025
b1fd548
alembic 対応
ivis-akaike Mar 6, 2025
c4d773c
Merge pull request #493 from ivis-akaike/w_oa_14_subrepository
ivis-akaike Mar 6, 2025
d2a6947
fix user admin view
ivis-ashino Mar 6, 2025
4d1bdc8
fix
ivis-ashino Mar 6, 2025
2875232
Merge pull request #496 from ivis-ashino/fix/subrepo
ivis-akaike Mar 7, 2025
d0e595e
fix community create_view
ivis-ashino Mar 7, 2025
1906399
workflow 初期データ登録修正
ivis-ashino Mar 7, 2025
f88ab12
Merge pull request #502 from ivis-ashino/fix/group_id
ivis-akaike Mar 7, 2025
02dc30f
fix userview create
ivis-ashino Mar 10, 2025
6005622
Merge pull request #508 from ivis-ashino/fix/userview
ivis-akaike Mar 10, 2025
72dd909
export_allのindex_id_listの処理を修正
ivis-ashino Mar 11, 2025
5fcc272
Merge branch 'feature/W2024-37_W-OA-06_0a14-merge' into w_oa_14_subre…
ivis-ashino Mar 11, 2025
27f61dd
Merge pull request #510 from ivis-weko3-dev/w_oa_14_subrepository
ivis-akaike Mar 11, 2025
678aa65
sitelisence_settings_viewを修正
ivis-ashino Mar 11, 2025
7182968
Merge pull request #514 from ivis-ashino/fix/admin_sitelicense_mail_s…
ivis-akaike Mar 11, 2025
c89269f
Merge pull request #511 from ivis-ashino/fix/export_all
ivis-akaike Mar 11, 2025
c9faf11
Merge pull request #515 from ivis-weko3-dev/w_oa_14_subrepository
ivis-akaike Mar 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 74 additions & 5 deletions modules/invenio-accounts/invenio_accounts/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,21 @@
from flask_admin.babel import lazy_gettext
from flask_admin.contrib.sqla import ModelView
from flask_admin.contrib.sqla.ajax import QueryAjaxModelLoader
from flask_admin.contrib.sqla.fields import QuerySelectMultipleField
from flask_admin.form import Select2Widget
from flask_admin.form.fields import DateTimeField
from flask_admin.model.fields import AjaxSelectMultipleField
from flask_babelex import gettext as _
from flask_security import current_user
from flask_security.recoverable import send_reset_password_instructions
from flask_security.utils import hash_password
from invenio_communities.models import Community
from invenio_db import db
from passlib import pwd
from sqlalchemy import func
from werkzeug.local import LocalProxy
from wtforms.fields import BooleanField
from collections import OrderedDict
from wtforms.fields import BooleanField, SelectMultipleField
from wtforms.validators import DataRequired

from weko_workflow.models import WorkFlow, WorkflowRole
Expand Down Expand Up @@ -52,7 +57,7 @@ class UserView(ModelView):
column_details_list = \
list_all

form_columns = ('email', 'password', 'active', 'roles', 'notification')
form_columns = ('email', 'password', 'active', 'notification')

form_args = dict(
email=dict(label='Email', validators=[DataRequired()]),
Expand All @@ -79,18 +84,77 @@ class UserView(ModelView):
'last_login_ip': _('Last Login IP')
}

def scaffold_form(self):
form_class = super(UserView, self).scaffold_form()
form_class.role = QuerySelectMultipleField(
'Roles',
query_factory=lambda: Role.query.filter(~Role.name.like('%_groups_%')).all(),
get_label='name',
widget=Select2Widget(multiple=True)
)
form_class.group = QuerySelectMultipleField(
'Groups',
query_factory=lambda: Role.query.filter(Role.name.like('%_groups_%')).all(),
get_label='name',
widget=Select2Widget(multiple=True)
)

return form_class

def _order_fields(self, form):
custom_order = ['email', 'password', 'active', 'role', 'group', 'notification']
ordered_fields = OrderedDict()
for field_name in custom_order:
ordered_fields[field_name] = form._fields[field_name]
form._fields = ordered_fields
return form

def create_form(self, obj=None):
form = super(UserView, self).create_form(obj)
return self._order_fields(form)

def edit_form(self, obj=None):
form = super(UserView, self).edit_form(obj)
return self._order_fields(form)

def on_form_prefill(self, form, id):
obj = self.get_one(id)
form.role.data = [role for role in obj.roles if '_groups_' not in role.name]
form.group.data = [role for role in obj.roles if '_groups_' in role.name]

def on_model_change(self, form, User, is_created):
"""Hash password when saving."""
if form.password.data is not None:
pwd_ctx = current_app.extensions['security'].pwd_context
if pwd_ctx.identify(form.password.data) is None:
User.password = hash_password(form.password.data)

roles = form.role.data + form.group.data
User.roles = roles

def after_model_change(self, form, User, is_created):
"""Send password instructions if desired."""
if is_created and form.notification.data is True:
send_reset_password_instructions(User)

def get_query(self):
"""Return a query for the model type."""
if any(role.name in current_app.config['WEKO_PERMISSION_SUPER_ROLE_USER'] for role in current_user.roles):
return self.session.query(self.model)
else:
repositories = Community.get_repositories_by_user(current_user)
groups = [repository.group for repository in repositories]
return self.session.query(self.model).filter(self.model.roles.any(Role.id.in_([group.id for group in groups])))

def get_count_query(self):
"""Return a the count query for the model type"""
if any(role.name in current_app.config['WEKO_PERMISSION_SUPER_ROLE_USER'] for role in current_user.roles):
return self.session.query(func.count('*')).select_from(self.model)
else:
repositories = Community.get_repositories_by_user(current_user)
groups = [repository.group for repository in repositories]
return self.session.query(func.count('*')).select_from(self.model).filter(self.model.roles.any(Role.id.in_([group.id for group in groups])))

@action('inactivate', _('Inactivate'),
_('Are you sure you want to inactivate selected users?'))
@commit
Expand Down Expand Up @@ -138,7 +202,12 @@ def action_activate(self, ids):

_system_role = os.environ.get('INVENIO_ROLE_SYSTEM',
'System Administrator')

_repo_role = os.environ.get('INVENIO_ROLE_REPOSITORY'
'Repository Administrator')
_com_role = os.environ.get('INVENIO_ROLE_COMMUNITY',
'Community Administrator')
_admin_roles = [_system_role, _repo_role, _com_role]

@property
def can_create(self):
"""Check permission for creating."""
Expand All @@ -147,12 +216,12 @@ def can_create(self):
@property
def can_edit(self):
"""Check permission for Editing."""
return self._system_role in [role.name for role in current_user.roles]
return any(role.name in self._admin_roles for role in current_user.roles)

@property
def can_delete(self):
"""Check permission for Deleting."""
return self._system_role in [role.name for role in current_user.roles]
return any(role.name in self._admin_roles for role in current_user.roles)


class RoleView(ModelView):
Expand Down
13 changes: 13 additions & 0 deletions modules/invenio-accounts/invenio_accounts/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from jwt import DecodeError, ExpiredSignatureError, decode, encode

from .errors import JWTDecodeError, JWTExpiredToken
from .models import User, userrole, Role


def jwt_create_token(user_id=None, additional_data=None):
Expand Down Expand Up @@ -85,3 +86,15 @@ def set_session_info(app, response, **extra):
response.headers['X-Session-ID'] = session_id
if current_user.is_authenticated:
response.headers['X-User-ID'] = current_user.get_id()


def get_user_ids_by_role(role_id):
"""Get user IDs by role ID.

Args:
role_id (int): The ID of the role.

Returns:
list: A list of user IDs associated with the given role.
"""
return [str(user.id) for user in User.query.join(userrole).join(Role).filter(Role.id == role_id).all()]
4 changes: 3 additions & 1 deletion modules/invenio-accounts/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from simplekv.memory.redisstore import RedisStore
from sqlalchemy_utils.functions import create_database, database_exists, \
drop_database
from weko_records_ui.config import WEKO_PERMISSION_SUPER_ROLE_USER

from invenio_accounts import InvenioAccounts
from invenio_accounts.admin import role_adminview, session_adminview, \
Expand Down Expand Up @@ -69,7 +70,8 @@ def _app_factory(config=None):
TESTING=True,
WTF_CSRF_ENABLED=False,
ACCOUNTS_JWT_ALOGORITHM = 'HS256',
ACCOUNTS_JWT_SECRET_KEY = 'None'
ACCOUNTS_JWT_SECRET_KEY = 'None',
WEKO_PERMISSION_SUPER_ROLE_USER = WEKO_PERMISSION_SUPER_ROLE_USER,
)

# Set key value session store to use Redis when running on TravisCI.
Expand Down
70 changes: 66 additions & 4 deletions modules/invenio-accounts/tests/test_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# under the terms of the MIT License; see LICENSE file for more details.

import pytest
from mock import patch
from mock import patch, MagicMock
from flask import current_app, session, url_for
from flask_admin import menu
from flask_security import url_for_security
Expand All @@ -17,9 +17,9 @@

from invenio_accounts import InvenioAccounts
from invenio_accounts.cli import users_create
from invenio_accounts.models import SessionActivity
from invenio_accounts.models import SessionActivity, User, Role
from invenio_accounts.testutils import create_test_user, login_user_via_view
from invenio_accounts.admin import SessionActivityView
from invenio_accounts.admin import SessionActivityView, UserView

_datastore = LocalProxy(
lambda: current_app.extensions['security'].datastore
Expand Down Expand Up @@ -220,4 +220,66 @@ def test_admin_sessions_action_delete(app):
view.action_delete([user1_sid])
sessions = SessionActivity.query.all()
assert len(sessions) == 1



# .tox/c1/bin/pytest --cov=invenio_accounts tests/test_admin.py::test_userview_get_query -vv -s --cov-branch --cov-report=term --basetemp=/code/modules/invenio-accounts/.tox/c1/tmp
def test_userview_get_query(app, users):
"""Test get_query for super role user."""
view = UserView(User, db.session)
mock_repo = MagicMock(group=MagicMock(id=1))
with app.test_request_context():
with patch("flask_login.utils._get_user", return_value=users[2]['obj']):
query = view.get_query()
assert query is not None
assert query.count() == User.query.count()

with patch("flask_login.utils._get_user", return_value=users[0]['obj']):
with patch("invenio_communities.models.Community.get_repositories_by_user", return_value=[mock_repo]):
db.session.add(users[0]['obj'])
db.session.commit()
query = view.get_query()
assert query is not None
assert query.count() == 0


# .tox/c1/bin/pytest --cov=invenio_accounts tests/test_admin.py::test_userview_get_count_query -vv -s --cov-branch --cov-report=term --basetemp=/code/modules/invenio-accounts/.tox/c1/tmp
def test_userview_get_count_query(app, users):
"""Test get_count_query for super role user."""
view = UserView(User, db.session)
mock_repo = MagicMock(group=MagicMock(id=1))
with app.test_request_context():
with patch("flask_login.utils._get_user", return_value=users[2]['obj']):
query = view.get_count_query()
assert query is not None
assert query.scalar() == User.query.count()

with patch("flask_login.utils._get_user", return_value=users[0]['obj']):
with patch("invenio_communities.models.Community.get_repositories_by_user", return_value=[mock_repo]):
db.session.add(users[0]['obj'])
db.session.commit()
query = view.get_count_query()
assert query is not None
assert query.scalar() == 0

# .tox/c1/bin/pytest --cov=invenio_accounts tests/test_admin.py::test_userview_on_form_prefill -vv -s --cov-branch --cov-report=term --basetemp=/code/modules/invenio-accounts/.tox/c1/tmp
def test_userview_on_form_prefill(app, users):
"""Test on_form_prefill for super role user."""
view = UserView(User, db.session)
form = view.create_form()
user = users[2]['obj']
user.roles = [
Role(name='role1'),
Role(name='role2_groups_1')
]
view.get_one = MagicMock(return_value=user)
view.on_form_prefill(form, user.id)
assert form.data['active'] is False
assert form.role.data == [user.roles[0]]
assert form.group.data == [user.roles[1]]

# .tox/c1/bin/pytest --cov=invenio_accounts tests/test_admin.py::test_userview_edit_form -vv -s --cov-branch --cov-report=term --basetemp=/code/modules/invenio-accounts/.tox/c1/tmp
def test_userview_edit_form(app, users):
"""Test edit_form for super role user."""
view = UserView(User, db.session)
form = view.edit_form()
assert form.data['active'] is False
32 changes: 31 additions & 1 deletion modules/invenio-accounts/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

from invenio_accounts import testutils
from invenio_accounts.errors import JWTDecodeError, JWTExpiredToken
from invenio_accounts.utils import jwt_create_token, jwt_decode_token
from invenio_accounts.utils import jwt_create_token, jwt_decode_token, get_user_ids_by_role


def test_client_authenticated(app):
Expand Down Expand Up @@ -172,3 +172,33 @@ def test_jwt_expired_token(app):
# Random token
with pytest.raises(JWTDecodeError):
jwt_decode_token('Roadster SV')


def test_get_user_ids_by_role_returns_user_ids(app):
"""Test get_user_ids_by_role."""
with app.app_context():
ds = app.extensions['invenio-accounts'].datastore

user1 = ds.create_user(email='test1@test.org', active=True)
user2 = ds.create_user(email='test2@test.org', active=True)
role = ds.create_role(name='superuser', description='1234')
ds.add_role_to_user(user1, role)
ds.add_role_to_user(user2, role)
ds.commit()

user_ids = get_user_ids_by_role(role.id)
assert str(user1.id) in user_ids
assert str(user2.id) in user_ids
assert len(user_ids) == 2


@pytest.mark.parametrize("role_id, expected", [
(999, []),
(None, []),
('1', []),
])
def test_get_user_ids_by_role_returns_empty_list(app, role_id, expected):
"""Test get_user_ids_by_role."""
with app.app_context():
user_ids = get_user_ids_by_role(role_id)
assert user_ids == expected
Loading
Loading