Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for syn:user and syn:role to repr/norm by name #3959

Merged
merged 8 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
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
5 changes: 5 additions & 0 deletions changes/8567a1e3122f571054749b76873466dc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
desc: Added support for ``syn:user`` and ``syn:role`` types to be converted to/from names.
prs: []
type: feat
...
5 changes: 5 additions & 0 deletions changes/ef5318e3f581ea3b4f60caf7c5c76c00.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
desc: Added ``$lib.repr()`` to convert a system mode value to a display mode string.
prs: []
type: feat
...
2 changes: 1 addition & 1 deletion synapse/cortex.py
Original file line number Diff line number Diff line change
Expand Up @@ -946,7 +946,7 @@ async def initServiceStorage(self):
self._exthttpapicache = s_cache.FixedCache(self._getHttpExtApiByPath, size=1000)
self._initCortexExtHttpApi()

self.model = s_datamodel.Model()
self.model = s_datamodel.Model(core=self)

await self._bumpCellVers('cortex:extmodel', (
(1, self._migrateTaxonomyIface),
Expand Down
3 changes: 2 additions & 1 deletion synapse/datamodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,8 +482,9 @@ class Model:
'''
The data model used by a Cortex hypergraph.
'''
def __init__(self):
def __init__(self, core=None):

self.core = core
self.types = {} # name: Type()
self.forms = {} # name: Form()
self.props = {} # (form,name): Prop() and full: Prop()
Expand Down
13 changes: 13 additions & 0 deletions synapse/lib/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,19 @@ async def getRoleByName(self, name):
def _getRoleIden(self, name):
return self.roleidenbyname.get(name)

# TODO convert getUserByName() and getRoleByName()
# back from async? These were plumbed to avoid infecting
# type norm/repr functions with async...
Comment on lines +267 to +269
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think we should do that when the deprecated auth:ctor config option is removed, no reason for them to be async

def _getRoleByName(self, name):
roleiden = self.roleidenbynamecache.get(name)
if roleiden is not None:
return self.role(roleiden)

def _getUserByName(self, name):
useriden = self.useridenbynamecache.get(name)
if useriden is not None:
return self.user(useriden)

@s_nexus.Pusher.onPushAuto('user:profile:set')
async def setUserProfileValu(self, iden, name, valu):
user = await self.reqUser(iden)
Expand Down
61 changes: 40 additions & 21 deletions synapse/lib/stormtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1328,6 +1328,22 @@ class LibBase(Lib):
),
'returns': {'type': 'list',
'desc': 'A list of (<bool>, <prim>) for status and normalized value.', }}},
{'name': 'repr', 'desc': '''
Attempt to convert a system mode value to a display mode string.

Examples:
Print the synapse user name for an iden::
Cisphyx marked this conversation as resolved.
Show resolved Hide resolved

$lib.print($lib.repr(syn:user, $iden))

''',
'type': {'type': 'function', '_funcname': '_repr',
'args': (
{'name': 'name', 'type': 'str', 'desc': 'The name of the model type.'},
{'name': 'valu', 'type': 'any', 'desc': 'The value to convert.'},
),
'returns': {'type': 'str', 'desc': 'A display mode representation of the value.'}}},

{'name': 'debug', 'desc': '''
True if the current runtime has debugging enabled.

Expand Down Expand Up @@ -1400,6 +1416,7 @@ def getObjLocals(self):
'false': False,
'text': self._text,
'cast': self._cast,
'repr': self._repr,
'warn': self._warn,
'print': self._print,
'raise': self._raise,
Expand Down Expand Up @@ -1489,22 +1506,26 @@ async def _copy(self, item):
mesg = 'Nested type does not support being copied!'
raise s_exc.BadArg(mesg=mesg) from None

def _reqTypeByName(self, name):
typeitem = self.runt.snap.core.model.type(name)
if typeitem is not None:
return typeitem

# If a type cannot be found for the form, see if name is a property
# that has a type we can use
propitem = self.runt.snap.core.model.prop(name)
if propitem is not None:
return propitem.type

mesg = f'No type or prop found for name {name}.'
raise s_exc.NoSuchType(mesg=mesg)

@stormfunc(readonly=True)
async def _cast(self, name, valu):
name = await toprim(name)
valu = await toprim(valu)

typeitem = self.runt.snap.core.model.type(name)
if typeitem is None:
# If a type cannot be found for the form, see if name is a property
# that has a type we can use
propitem = self.runt.snap.core.model.prop(name)
if propitem is None:
mesg = f'No type or prop found for name {name}.'
raise s_exc.NoSuchType(mesg=mesg)

typeitem = propitem.type

typeitem = self._reqTypeByName(name)
# TODO an eventual mapping between model types and storm prims

norm, info = typeitem.norm(valu)
Expand All @@ -1515,23 +1536,21 @@ async def trycast(self, name, valu):
name = await toprim(name)
valu = await toprim(valu)

typeitem = self.runt.snap.core.model.type(name)
if typeitem is None:
# If a type cannot be found for the form, see if name is a property
# that has a type we can use
propitem = self.runt.snap.core.model.prop(name)
if propitem is None:
mesg = f'No type or prop found for name {name}.'
raise s_exc.NoSuchType(mesg=mesg)

typeitem = propitem.type
typeitem = self._reqTypeByName(name)

try:
norm, info = typeitem.norm(valu)
return (True, fromprim(norm, basetypes=False))
except s_exc.BadTypeValu:
return (False, None)

@stormfunc(readonly=True)
async def _repr(self, name, valu):
name = await toprim(name)
valu = await toprim(valu)

return self._reqTypeByName(name).repr(valu)

@stormfunc(readonly=True)
async def _exit(self, mesg=None, **kwargs):
if mesg:
Expand Down
1 change: 0 additions & 1 deletion synapse/models/media.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ def getModelDefs(self):
('publisher', ('ou:org', {}), {
'doc': 'The organization which published the news.'}),


('publisher:name', ('ou:name', {}), {
'doc': 'The name of the publishing org used to publish the news.'}),

Expand Down
70 changes: 64 additions & 6 deletions synapse/models/syn.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,67 @@

import synapse.exc as s_exc

import synapse.lib.types as s_types
import synapse.lib.module as s_module

logger = logging.getLogger(__name__)

class SynUser(s_types.Guid):

def _normPyStr(self, text):

core = self.modl.core
if core is not None:

# direct use of an iden takes precedence...
user = core.auth.user(text)
if user is not None:
return user.iden, {}

user = core.auth._getUserByName(text)
if user is not None:
return user.iden, {}

return s_types.Guid._normPyStr(self, text)

def repr(self, iden):

core = self.modl.core
if core is not None:
user = core.auth.user(iden)
if user is not None:
return user.name

return iden

class SynRole(s_types.Guid):

def _normPyStr(self, text):

core = self.modl.core
if core is not None:

# direct use of an iden takes precedence...
role = core.auth.role(text)
if role is not None:
return role.iden, {}

role = core.auth._getRoleByName(text)
if role is not None:
return role.iden, {}

return s_types.Guid._normPyStr(self, text)

Check warning on line 54 in synapse/models/syn.py

View check run for this annotation

Codecov / codecov/patch

synapse/models/syn.py#L54

Added line #L54 was not covered by tests

def repr(self, iden):

core = self.modl.core
if core is not None:
role = core.auth.role(iden)
if role is not None:
return role.name

return iden

Check warning on line 64 in synapse/models/syn.py

View check run for this annotation

Codecov / codecov/patch

synapse/models/syn.py#L64

Added line #L64 was not covered by tests

class SynModule(s_module.CoreModule):

def initCoreModule(self):
Expand Down Expand Up @@ -105,6 +162,13 @@

return (('syn', {

'ctors': (
('syn:user', 'synapse.models.syn.SynUser', {}, {
'doc': 'A Synapse user.'}),

('syn:role', 'synapse.models.syn.SynRole', {}, {
'doc': 'A Synapse role.'}),
),
'types': (
('syn:type', ('str', {'strip': True}), {
'doc': 'A Synapse type used for normalizing nodes and properties.',
Expand All @@ -130,12 +194,6 @@
('syn:nodedata', ('comp', {'fields': (('key', 'str'), ('form', 'syn:form'))}), {
'doc': 'A nodedata key and the form it may be present on.',
}),
('syn:user', ('guid', {'strip': True}), {
'doc': 'A Synapse user GUID.'
}),
('syn:role', ('guid', {'strip': True}), {
'doc': 'A Synapse role GUID.'
}),
),

'forms': (
Expand Down
43 changes: 43 additions & 0 deletions synapse/tests/test_model_syn.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import synapse.exc as s_exc
import synapse.common as s_common
import synapse.cortex as s_cortex
import synapse.datamodel as s_datamodel

import synapse.lib.stormsvc as s_stormsvc

Expand Down Expand Up @@ -46,6 +48,47 @@ class TestService(s_stormsvc.StormSvc):

class SynModelTest(s_t_utils.SynTest):

async def test_syn_userrole(self):

async with self.getTestCore() as core:

(ok, iden) = await core.callStorm('return($lib.trycast(syn:user, root))')
self.true(ok)
self.eq(iden, core.auth.rootuser.iden)

# coverage for iden taking precedence
(ok, iden) = await core.callStorm(f'return($lib.trycast(syn:user, {iden}))')
self.true(ok)
self.eq(iden, core.auth.rootuser.iden)

self.eq('root', await core.callStorm(f'return($lib.repr(syn:user, {iden}))'))

(ok, iden) = await core.callStorm('return($lib.trycast(syn:role, all))')
self.true(ok)
self.eq(iden, core.auth.allrole.iden)

# coverage for iden taking precedence
(ok, iden) = await core.callStorm(f'return($lib.trycast(syn:role, {iden}))')
self.true(ok)
self.eq(iden, core.auth.allrole.iden)

self.eq('all', await core.callStorm(f'return($lib.repr(syn:role, {iden}))'))

# coverage for DataModel without a cortex reference
iden = s_common.guid()

model = core.model
model.core = None

synuser = model.type('syn:user')
synrole = model.type('syn:user')

self.eq(iden, synuser.repr(iden))
self.eq(iden, synrole.repr(iden))

self.eq(iden, synuser.norm(iden)[0])
self.eq(iden, synrole.norm(iden)[0])

async def test_syn_tag(self):

async with self.getTestCore() as core:
Expand Down
Loading