jesustorresdev / slack-badges-bot

2 stars 1 forks source link

Caché para api slack con cachetools y comandos /badges list @Usuario y /badges help #14

Closed mbdaso closed 5 years ago

mbdaso commented 5 years ago

Con esto ya se pueden crear medallas, listarlas, darlas a un usuario y listar las medallas que tiene un usuario. Qué más faltaría?

jesustorresdev commented 5 years ago

¿Qué cosas de esas se pueden hacer desde en bot y cuales desde en comando? A ver de que da tiempo:

https://www.imsglobal.org/sites/default/files/Badges/OBv2p0Final/index.html

Por ejemplo la app debe exponer una perfil des issuer en una url. Como la info es fija la información necesaria podría indicarse en la configuracion (nombre del issuer, etc)

Los badges puden tener idioma (esto no es tan, podria ponerlo como issue y en la memoria indica que es línea futura)

¿Que tipo de emision se hace? Hosted o fimada. La firmada parece más interesante pero ambas tienen sus requisitos. En la hosted los badges y los assertion tiene una url. Y hay una url donde se puede verificar la assertione. En los signed los badges se recomienda que tengan su url pero el assertion puede usar como id uuid y no hay que alojarlos. Los assertion llevan instrucciones de cómo se hace la validación y en issuer profile tambien.

En resumen, deberías mirar en estándar a ver si tienes lo mínimo para que funcione.

mbdaso commented 5 years ago

¿Qué cosas de esas se pueden hacer desde en bot y cuales desde en comando?

Crear una medalla se hace desde la línea de comandos, desde el bot se pueden las otras 3 cosas: asignar, listar medallas y listar asignaciones de medallas

A ver de que da tiempo:

  • Borrar una medalla. Eso no se las debería quitar a nadie. La émitidas emitidas están. Quizas no sea borrar sino hide. que le ponga una marca para ocultarlas al listar y que no se puedan asigrnar

Borrar una medalla supondría borrar todas las asignaciones que tiene porque en el "Badge Assertion" (asignacion de la medalla) va una url que apunta al "Badge Class" (medalla): http://vituin-chat.iaas.ull.es/api/awards/6e285ba924eb42eaa2a043cd7593ef39/json

{
uid: "6e285ba924eb42eaa2a043cd7593ef39",
recipient: {
type: "email",
hashed: false,
identity: "jmtorres@ull.edu.es"
},
badge: "http://vituin-chat.iaas.ull.es/api/badges/f286b11ad2ab4915b56c6f7fc47722c0/json",
verify: {
type: "hosted",
url: "http://vituin-chat.iaas.ull.es/api/awards/6e285ba924eb42eaa2a043cd7593ef39/json"
},
issuedOn: "2019-08-19T15:37:02.127059",
image: "http://vituin-chat.iaas.ull.es/api/awards/6e285ba924eb42eaa2a043cd7593ef39/image"
}
mbdaso commented 5 years ago
  • ¿Tiene sentido modifica una medalla creada? Cambiar nombre, imagen. No debe afectar a las emitadas.

Si se modifica una medalla afectaría a las emitidas. Si la idea es modificar una medalla sin que afecte a las emitidas, por qué no crear una nueva?

  • ¿Lista personas con medalla? ¿Las medallas se asignan a correos o como?

Sí, cuando se emite una medalla es básicamente asignar la medalla con un correo y una fecha de emisión. https://github.com/mozilla/openbadges-specification/blob/master/Assertion/latest.md#badgeassertion

  • Aparte de lo dicho ¿has revisado los requisitos del estándar?

https://www.imsglobal.org/sites/default/files/Badges/OBv2p0Final/index.html

Por ejemplo la app debe exponer una perfil des issuer en una url. Como la info es fija la información necesaria podría indicarse en la configuracion (nombre del issuer, etc)

Lo hice yo a mano, y se maneja con services.issuer http://vituin-chat.iaas.ull.es/api/issuer

Los badges puden tener idioma (esto no es tan, podria ponerlo como issue y en la memoria indica que es línea futura)

¿Que tipo de emision se hace? Hosted o fimada. La firmada parece más interesante pero ambas tienen sus requisitos. En la hosted los badges y los assertion tiene una url. Y hay una url donde se puede verificar la assertione. En los signed los badges se recomienda que tengan su url pero el assertion puede usar como id uuid y no hay que alojarlos. Los assertion llevan instrucciones de cómo se hace la validación y en issuer profile tambien.

Estoy usando hosted, por lo que veo aquí la firmada sólo es cambiar la url del parámetro "verify" por la clave pública, pero no veo cual es la ventaja de hacer eso. https://github.com/mozilla/openbadges-backpack/wiki/Creating-Signed-Assertions

En resumen, deberías mirar en estándar a ver si tienes lo mínimo para que funcione.

En principio sí, se pueden validar aquí tanto la medalla como la imagen cocinada de la medalla https://openbadgesvalidator.imsglobal.org/

http://vituin-chat.iaas.ull.es/api/awards/6e285ba924eb42eaa2a043cd7593ef39/json

mbdaso commented 5 years ago

yo creo que lo más importante que hace falta ahora es algo para retringir el uso del comando en slack, una especie de panel de administración o algo así. ¿Qué se puede hacer?

jesustorresdev commented 5 years ago

Crear una medalla se hace desde la línea de comandos, desde el bot se pueden las otras 3 cosas: asignar, listar medallas y listar asignaciones de medallas

Creo que el uso normal es que desde la linea de comandos se pueda hacer de todo. Desde slack las 3 cosas que indicas.

jesustorresdev commented 5 years ago

Si se modifica una medalla afectaría a las emitidas. Si la idea es modificar una medalla sin que afecte a las emitidas, por qué no crear una nueva?

Por que puedes crear una, hacerlo mala y ver obligado a crear otra.

Parece que sería interesante al menos permitir el borrado de las medallas que no se han asignado a nadie aún. Luego se podría crear de nuevo. corregida.

Desde un punto de vista del usuario lo ideal sería permitir también editar. Igualmente, sólo si no ha sido dada a nadie.

jesustorresdev commented 5 years ago

Sí, cuando se emite una medalla es básicamente asignar la medalla con un correo y una fecha de emisión. https://github.com/mozilla/openbadges-specification/blob/master/Assertion/latest.md#badgeassertion

Un posible mejora sería tener una entidad Persona donda una misma persona pueda tener sus multiples emails, telefonos y otras formas de identificación.

Pero veo más bien eso como una característica futura.

jesustorresdev commented 5 years ago

Lo hice yo a mano, y se maneja con services.issuer http://vituin-chat.iaas.ull.es/api/issuer

Este es un caso que no necesita una entidad ni un servicio. No es algo propio del negocio de gestionar medillas. Es propio de la implementación de openbadges.

Se puede generar esa JSON con usa URL el adapto que da servicio al api openbadges porque es algo específico de esa API.

Ese adaptado / servicio web genera el JSON usando el nombre y descripción que lee de la configuación. Para las url se debe usar url_for() para genera la URL adecuada. Así el Issue se genera siempre bien aunque se cambie el dominio. No se deben usar URL hard-coded

Eso hace que me fije en algo. Las URL guardadas en JSON son absolutas. Debería ser los id de las entidades. Y el API del web service debe usar también esos id para identificar cosas. Solo deberá usarse una URL completa cuando se va a generar un JSON para OpenBadges. Y para esa URL se debe usar url_for()

Mirando al codigo veo que hemos mezclado dos cosas que debería estar separadas. Por una lado debería estar el API que usa el cliente de linea de comandos para gestionar el servicio. En este API el JSON puede ser parecido a las entidades que tenemos y es donde estan acciones como borrar, crear, etc.

Luego debería estar la interfaz que pide OpenBadges, que deberá ser otro web service. Sus JSON deben ser tal y como los indica el estándar. Y no debe permitir crear cosas ni asignada nada a nadie.

Creo que es algo que hablamos varias veces pero que esta separación se ido perdiendo segun avanza el proyecto. El tema es que es importante para separar el proyecto de un estándar concreto. Asi el servicio puede hablar con quienes entienden openbadges pero también quienes entienden otras cosas.

mbdaso commented 5 years ago

Sí, cuando se emite una medalla es básicamente asignar la medalla con un correo y una fecha de emisión. https://github.com/mozilla/openbadges-specification/blob/master/Assertion/latest.md#badgeassertion

Un posible mejora sería tener una entidad Persona donda una misma persona pueda tener sus multiples emails, telefonos y otras formas de identificación.

Pero veo más bien eso como una característica futura.

Hay una entidad para las personas

@dataclass
class Person:
    id: EntityID
    email: str
    slack_id: str
    slack_name: str

    @property
    def id_str(self):
        return str(self.id.hex)

Y se guardan cuando se emite una medalla a una persona nueva: (en services.award.create_award:)

...
person = self.person_service.person_byemail(email)
        if not person:
            person = self.person_service.create_person(slack_name, slack_id, email)
...
jesustorresdev commented 5 years ago

Estoy usando hosted, por lo que veo aquí la firmada sólo es cambiar la url del parámetro "verify" por la clave pública, pero no veo cual es la ventaja de hacer eso. https://github.com/mozilla/openbadges-backpack/wiki/Creating-Signed-Assertions

Que no hay que hacer hosting de las medallas asignadas. Se mandan firmadas, alguien las almacena y se comprueba con la firma. Cada assertion no necesita un assert ni hay que recordarlas para siempre.

Supongo que puede ser algo para una mejora futura.

jesustorresdev commented 5 years ago

http://vituin-chat.iaas.ull.es/api/awards/6e285ba924eb42eaa2a043cd7593ef39/json

Por qué las URL que devuelven un JSON terminan en /json y las que devuelven una imagen en image. O es algo común.

jesustorresdev commented 5 years ago

Hay una entidad para las personas

Estupendo. Así está bien. Extenderlo para admitir varios correos en el futuro no sería problema.

Pregunta. ¿El slack_id es el identificador en el servicio y el slack_name es su nombre o el correo / user name? Entiendo que el bot de un usuario al que haces referencia te da el id o que?

jesustorresdev commented 5 years ago

yo creo que lo más importante que hace falta ahora es algo para retringir el uso del comando en slack, una especie de panel de administración o algo así. ¿Qué se puede hacer?

¿Puedes enterare de si un usuario es admin / owner del slack. Se podría hacer que asignar solo se para el propietario del canal.

jesustorresdev commented 5 years ago

Mirando la documentación hay un app home para hablar con el bot:

https://api.slack.com/reference/app-home

Podría ser el sitio para configurar cosas privadas. Por ejemplo, para decirle quién puede asignar medallas. Podría ser solo el admin, todos, los miembros de un grupo concreto.

jesustorresdev commented 5 years ago

En principo no veo motivo para limitar sacar la lista de badges por todos y de bages ganados.

Pero es posible que alguien quiera que la lista sea secreta. Y alguien puede querer que solo puedas consultas los badges asignados a ti. No poder listar todos los de alguien en concreto. E incluso que que si puedas pero solo en la App Home.

Muchas opciones veo yo.

mbdaso commented 5 years ago

Lo hice yo a mano, y se maneja con services.issuer http://vituin-chat.iaas.ull.es/api/issuer

Este es un caso que no necesita una entidad ni un servicio. No es algo propio del negocio de gestionar medillas. Es propio de la implementación de openbadges.

Pero de alguna manera tengo que tener persistencia de los datos que tengo que poner: https://github.com/mozilla/openbadges-specification/blob/master/Assertion/latest.md#issuerorganization Como lo hago sin un repositorio?

Se puede generar esa JSON con usa URL el adapto que da servicio al api openbadges porque es algo específico de esa API.

Ese adaptado / servicio web genera el JSON usando el nombre y descripción que lee de la configuación. Para las url se debe usar url_for() para genera la URL adecuada. Así el Issue se genera siempre bien aunque se cambie el dominio. No se deben usar URL hard-coded

Eso hace que me fije en algo. Las URL guardadas en JSON son absolutas. Debería ser los id de las entidades. Y el API del web service debe usar también esos id para identificar cosas. Solo deberá usarse una URL completa cuando se va a generar un JSON para OpenBadges. Y para esa URL se debe usar url_for()

La única hardcoded es la del issuer porque sólo hay uno: https://github.com/alu0100832211/slack-badges-bot/blob/ab275c05e7644acebf6fb35161a9677c35f6875c/slack_badges_bot/adapters/api.py#L190

self.app.router.add_post('/badges/create', self.create_badge_handler)
        self.app.router.add_get('/badges/{badge_id}/{requested_data}', self.badge_handler)
        self.app.router.add_get('/issuer', self.issuer_handler)
        self.app.router.add_get('/awards/{award_id}/{requested_data}', self.award_handler)

Luego en los handlers hago:

            badge_id = request.match_info['badge_id']
            requested_data = request.match_info['requested_data']

https://github.com/alu0100832211/slack-badges-bot/blob/ab275c05e7644acebf6fb35161a9677c35f6875c/slack_badges_bot/adapters/api.py#L139

Pero podría ponerle un id al issuer tambien y cambiar esto

        self.app.router.add_get('/issuer', self.issuer_handler)

por esto

        self.app.router.add_get('/issuer/{issuer_id}', self.issuer_handler)

Mirando al codigo veo que hemos mezclado dos cosas que debería estar separadas. Por una lado debería estar el API que usa el cliente de linea de comandos para gestionar el servicio. En este API el JSON puede ser parecido a las entidades que tenemos y es donde estan acciones como borrar, crear, etc.

Luego debería estar la interfaz que pide OpenBadges, que deberá ser otro web service. Sus JSON deben ser tal y como los indica el estándar. Y no debe permitir crear cosas ni asignada nada a nadie.

Creo que es algo que hablamos varias veces pero que esta separación se ido perdiendo segun avanza el proyecto. El tema es que es importante para separar el proyecto de un estándar concreto. Asi el servicio puede hablar con quienes entienden openbadges pero también quienes entienden otras cosas.

Vale, voy a separar eso, justo estaba pensando en poner para la línea de comandos algo como api/admin/create/... y para el resto api/...

jesustorresdev commented 5 years ago

En principo no veo motivo para limitar sacar la lista de badges por todos y de bages ganados.

Pero es posible que alguien quiera que la lista sea secreta. Y alguien puede querer que solo puedas consultas los badges asignados a ti. No poder listar todos los de alguien en concreto. E incluso que que si puedas pero solo en la App Home.

Muchas opciones veo yo.

Pienso el caso más típico y te digo.

mbdaso commented 5 years ago

http://vituin-chat.iaas.ull.es/api/awards/6e285ba924eb42eaa2a043cd7593ef39/json

Por qué las URL que devuelven un JSON terminan en /json y las que devuelven una imagen en image. O es algo común.

por esto:

async def badge_handler(self, request):
        try:
            badge_id = request.match_info['badge_id']
            requested_data = request.match_info['requested_data']
            ...
            if requested_data == 'image':
                ...
            elif requested_data == 'json':
                ...
            elif requested_data == 'criteria':
               ...
            else:
                response = web.HTTPBadRequest()

Me pareció mejor que poner .json y .png pero tambien podria ponerlo

jesustorresdev commented 5 years ago

Vale, voy a separar eso, justo estaba pensando en poner para la línea de comandos algo como api/admin/create/... y para el resto api/...

Tengo que salir. Miro todo lo demás luego y te digo.

Yo, para seguir la filosofia esta, separari Tendria WebService por un lado con el api en /api que es lo típico. Y un OpenBadgesWebService con el web services de OpenBadges en openbadges/. Así se pueden añadir adapters a otros servicios similares en el futuro

jesustorresdev commented 5 years ago

Pero de alguna manera tengo que tener persistencia de los datos que tengo que poner: https://github.com/mozilla/openbadges-specification/blob/master/Assertion/latest.md#issuerorganization Como lo hago sin un repositorio?

Los repositorios son para datos dinámicos. Como lo que meterías en una base de datos. Los datos de un badge que el usuario creo.

Pero el issuer es algo estático. No cambia nunca. Podrías tener el JSON hardcoded si quisieras. LO unido que digo es que tengas una configuracion que es OPENBADGE_ISSUER_NAME y OPENBADGET_ISSUER_DESCRIPTION y que generes al JSON de issuer en openbadge/issuer con esa info.

La info de issuer no es del dominio. No hay nada en la lógica de la aplicación que tenga que saber de issuer. Lo de publicar la info de un issuer depende de openbadges, luego es algo de adaptor de openbadges. Otros adaptores pueden necesitar otra información que es diferente y específica de su API. EL hecho de que los datos sean fijos nos debe hacer pensar que no es cosa del dominio de la app ni de su lógica de negocio

jesustorresdev commented 5 years ago

La única hardcoded es la del issuer porque sólo hay uno: https://github.com/alu0100832211/slack-badges-bot/blob/ab275c05e7644acebf6fb35161a9677c35f6875c/slack_badges_bot/adapters/api.py#L190

self.app.router.add_post('/badges/create', self.create_badge_handler)
        self.app.router.add_get('/badges/{badge_id}/{requested_data}', self.badge_handler)
        self.app.router.add_get('/issuer', self.issuer_handler)
        self.app.router.add_get('/awards/{award_id}/{requested_data}', self.award_handler)

Luego en los handlers hago:

            badge_id = request.match_info['badge_id']
            requested_data = request.match_info['requested_data']

https://github.com/alu0100832211/slack-badges-bot/blob/ab275c05e7644acebf6fb35161a9677c35f6875c/slack_badges_bot/adapters/api.py#L139

Pero podría ponerle un id al issuer tambien y cambiar esto

        self.app.router.add_get('/issuer', self.issuer_handler)

por esto

        self.app.router.add_get('/issuer/{issuer_id}', self.issuer_handler)

ENtonces un badge que guarda para saber cuál es su imagen en el JSON del repo? Y un award en el JSON del repo, como sabe cual es el badge?

jesustorresdev commented 5 years ago

Me pareció mejor que poner .json y .png pero tambien podria ponerlo

No se suele indicar el formato en la URL de ningun manera a menos que es que el cliente puede elegir formato. Por ejemplo que si la URL es /xml es que el formato es XML. Pero no es el caso

jesustorresdev commented 5 years ago

Mirando la documentación hay un app home para hablar con el bot:

https://api.slack.com/reference/app-home

Podría ser el sitio para configurar cosas privadas. Por ejemplo, para decirle quién puede asignar medallas. Podría ser solo el admin, todos, los miembros de un grupo concreto.

Creo que los casos de uso son:

  1. El admin / puede hacer cualquier operación desde el app home y desde cualquier canal. Asi lo ven todos.
  2. Un usuario normal solo puede consulta sus badges ganados por el app home. No los de los demmás.
  3. Que los usuarios pueda pedir la lista de bades disponibles por el app home, puede ser algo en la configuración.
jesustorresdev commented 5 years ago

Imagino que la intefaz del bot muestra algo de texto. Será bueno usar esto para ayudar a la futura traducción de esos textos.

Basicamente es lo de:

import gettext t = gettext.translation('nombre_delproyecto') = t.gettext

Y luego donde haya una cadena que deba ser traducida _("Cadena")

mbdaso commented 5 years ago

ENtonces un badge que guarda para saber cuál es su imagen en el JSON del repo? Y un award en el JSON del repo, como sabe cual es el badge?

Porque guarda los ids, y luego construyo las URLs con esos ids: https://github.com/aplatanado/slack-badges-bot/blob/c8662df449fd6c1fa124fae6023a7b03b593c174/slack_badges_bot/entities/entities.py#L58

https://github.com/aplatanado/slack-badges-bot/blob/c8662df449fd6c1fa124fae6023a7b03b593c174/slack_badges_bot/utils/openbadges.py#L28

mbdaso commented 5 years ago

Si quieres podemos hacer un hangouts para resolver mejor las dudas

jesustorresdev commented 5 years ago

Porque guarda los ids, y luego construyo las URLs con esos ids: https://github.com/aplatanado/slack-badges-bot/blob/c8662df449fd6c1fa124fae6023a7b03b593c174/slack_badges_bot/entities/entities.py#L58

Vale. Es que el JSON que yo vi era una respuesta no del repo. Estupendo asií.

https://github.com/aplatanado/slack-badges-bot/blob/c8662df449fd6c1fa124fae6023a7b03b593c174/slack_badges_bot/utils/openbadges.py#L28

Ok. Pus para generar la URL no suele ser así porque al final tienes la cadena de la URL para los badges en dos sitios. En BADGES_JSON_URL y aquí:

 self.app.router.add_get('/badges/{badge_id}/{requested_data}', self.badge_handler)

Configurar las rutas requiere cambiar en dos lugares. Por eso se usa url_for. Con:

self.app.router.add_get('/badges/{badge_id}/{requested_data}', self.badge_handler, name='badges')
...
app.route['badges'].url_for(badges_id=id, requested_data=<loquesea>)

Como ves se asigna un nombre a la ruta.

mbdaso commented 5 years ago
self.app.router.add_get('/badges/{badge_id}/{requested_data}', self.badge_handler, name='badges')
...
app.route['badges'].url_for(badges_id=id, requested_data=<loquesea>)

Como ves se asigna un nombre a la ruta.

Te refieres a poner eso en la configuración? Eso sería pasarle algo de la capa de infraestructura (app) a la capa de aplicación (ConfigService), habría una dependencia y se perdería la estructura, no?