mirror of
https://shylinux.com/x/community
synced 2025-07-01 13:14:44 +08:00
add smh
This commit is contained in:
parent
36c8e4e36e
commit
973c7c024c
@ -4,7 +4,9 @@ const GONGANXITONG_PORTAL = "web.team.gonganxitong.portal"
|
||||
const GONGANXITONG_ALLOW = "web.team.gonganxitong.allow"
|
||||
const GONGANXITONG_APPLY = "web.team.gonganxitong.apply"
|
||||
const GONGANXITONG_CITY = "web.team.gonganxitong.city"
|
||||
const GONGANXITONG_CONTRACT = "web.team.gonganxitong.contract"
|
||||
const GONGANXITONG_CREDIT = "web.team.gonganxitong.credit"
|
||||
const GONGANXITONG_DOCUMENT = "web.team.gonganxitong.document"
|
||||
const GONGANXITONG_DOMAIN = "web.team.gonganxitong.domain"
|
||||
const GONGANXITONG_EMAIL = "web.team.gonganxitong.email"
|
||||
const GONGANXITONG_EVENT = "web.team.gonganxitong.event"
|
||||
@ -14,6 +16,7 @@ const GONGANXITONG_MEMBER = "web.team.gonganxitong.member"
|
||||
const GONGANXITONG_MESSAGE = "web.team.gonganxitong.message"
|
||||
const GONGANXITONG_NOTICE = "web.team.gonganxitong.notice"
|
||||
const GONGANXITONG_PAYMENTLIST = "web.team.gonganxitong.paymentlist"
|
||||
const GONGANXITONG_PHOTO = "web.team.gonganxitong.photo"
|
||||
const GONGANXITONG_QRCODE = "web.team.gonganxitong.qrcode"
|
||||
const GONGANXITONG_RECENT = "web.team.gonganxitong.recent"
|
||||
const GONGANXITONG_SERVICE = "web.team.gonganxitong.service"
|
||||
@ -25,7 +28,9 @@ const HUODONGZUZHI_ACTIVITY = "web.team.huodongzuzhi.activity"
|
||||
const HUODONGZUZHI_PORTAL = "web.team.huodongzuzhi.portal"
|
||||
const HUODONGZUZHI_ALLOW = "web.team.huodongzuzhi.allow"
|
||||
const HUODONGZUZHI_APPLY = "web.team.huodongzuzhi.apply"
|
||||
const HUODONGZUZHI_CONTRACT = "web.team.huodongzuzhi.contract"
|
||||
const HUODONGZUZHI_CREDIT = "web.team.huodongzuzhi.credit"
|
||||
const HUODONGZUZHI_DOCUMENT = "web.team.huodongzuzhi.document"
|
||||
const HUODONGZUZHI_EVENT = "web.team.huodongzuzhi.event"
|
||||
const HUODONGZUZHI_MARKET = "web.team.huodongzuzhi.market"
|
||||
const HUODONGZUZHI_MEETING = "web.team.huodongzuzhi.meeting"
|
||||
@ -33,6 +38,7 @@ const HUODONGZUZHI_MEMBER = "web.team.huodongzuzhi.member"
|
||||
const HUODONGZUZHI_MESSAGE = "web.team.huodongzuzhi.message"
|
||||
const HUODONGZUZHI_NOTICE = "web.team.huodongzuzhi.notice"
|
||||
const HUODONGZUZHI_PAYMENTLIST = "web.team.huodongzuzhi.paymentlist"
|
||||
const HUODONGZUZHI_PHOTO = "web.team.huodongzuzhi.photo"
|
||||
const HUODONGZUZHI_QRCODE = "web.team.huodongzuzhi.qrcode"
|
||||
const HUODONGZUZHI_RECENT = "web.team.huodongzuzhi.recent"
|
||||
const HUODONGZUZHI_SERVICE = "web.team.huodongzuzhi.service"
|
||||
@ -44,10 +50,17 @@ const RENZHENGSHOUQUAN_ALLOW = "web.team.renzhengshouquan.allow"
|
||||
const RENZHENGSHOUQUAN_APPLY = "web.team.renzhengshouquan.apply"
|
||||
const RENZHENGSHOUQUAN_AUTH = "web.team.renzhengshouquan.auth"
|
||||
const RENZHENGSHOUQUAN_CERT = "web.team.renzhengshouquan.cert"
|
||||
const RENZHENGSHOUQUAN_CONTRACT = "web.team.renzhengshouquan.contract"
|
||||
const RENZHENGSHOUQUAN_CREDIT = "web.team.renzhengshouquan.credit"
|
||||
const RENZHENGSHOUQUAN_DOCUMENT = "web.team.renzhengshouquan.document"
|
||||
const RENZHENGSHOUQUAN_DOMAIN = "web.team.renzhengshouquan.domain"
|
||||
const RENZHENGSHOUQUAN_EVENT = "web.team.renzhengshouquan.event"
|
||||
const RENZHENGSHOUQUAN_EXTERNAL_TENCENT_MEETING = "web.team.renzhengshouquan.external.tencent.meeting"
|
||||
const RENZHENGSHOUQUAN_EXTERNAL_TENCENTCLOUD_REALNAME_REALNAM = "web.team.renzhengshouquan.external.tencentcloud.realname.realnam"
|
||||
const RENZHENGSHOUQUAN_EXTERNAL_TENCENTCLOUD_SMH_SMH = "web.team.renzhengshouquan.external.tencentcloud.smh.smh"
|
||||
const RENZHENGSHOUQUAN_EXTERNAL_TENCENTCLOUD_SMS_SMS = "web.team.renzhengshouquan.external.tencentcloud.sms.sms"
|
||||
const RENZHENGSHOUQUAN_EXTERNAL_TENCENTCLOUD_TENCENTCLOUD = "web.team.renzhengshouquan.external.tencentcloud.tencentcloud"
|
||||
const RENZHENGSHOUQUAN_EXTERNAL_TENCENTDOCUMENT_TENCENTDOCUME = "web.team.renzhengshouquan.external.tencentdocument.tencentdocume"
|
||||
const RENZHENGSHOUQUAN_EXTERNAL_TENCENTMEETING_TENCENTMEETING = "web.team.renzhengshouquan.external.tencentmeeting.tencentmeeting"
|
||||
const RENZHENGSHOUQUAN_EXTERNAL_WEIXINPAYMENT_WEIXINPAYMENT = "web.team.renzhengshouquan.external.weixinpayment.weixinpayment"
|
||||
const RENZHENGSHOUQUAN_MARKET = "web.team.renzhengshouquan.market"
|
||||
@ -56,6 +69,7 @@ const RENZHENGSHOUQUAN_MEMBER = "web.team.renzhengshouquan.member"
|
||||
const RENZHENGSHOUQUAN_MESSAGE = "web.team.renzhengshouquan.message"
|
||||
const RENZHENGSHOUQUAN_NOTICE = "web.team.renzhengshouquan.notice"
|
||||
const RENZHENGSHOUQUAN_PAYMENTLIST = "web.team.renzhengshouquan.paymentlist"
|
||||
const RENZHENGSHOUQUAN_PHOTO = "web.team.renzhengshouquan.photo"
|
||||
const RENZHENGSHOUQUAN_PROFILE = "web.team.renzhengshouquan.profile"
|
||||
const RENZHENGSHOUQUAN_QRCODE = "web.team.renzhengshouquan.qrcode"
|
||||
const RENZHENGSHOUQUAN_RECENT = "web.team.renzhengshouquan.recent"
|
||||
@ -66,7 +80,9 @@ const YUEHAOXITONG_PORTAL = "web.team.yuehaoxitong.portal"
|
||||
const YUEHAOXITONG_ALLOW = "web.team.yuehaoxitong.allow"
|
||||
const YUEHAOXITONG_APPLY = "web.team.yuehaoxitong.apply"
|
||||
const YUEHAOXITONG_CALL = "web.team.yuehaoxitong.call"
|
||||
const YUEHAOXITONG_CONTRACT = "web.team.yuehaoxitong.contract"
|
||||
const YUEHAOXITONG_CREDIT = "web.team.yuehaoxitong.credit"
|
||||
const YUEHAOXITONG_DOCUMENT = "web.team.yuehaoxitong.document"
|
||||
const YUEHAOXITONG_EVENT = "web.team.yuehaoxitong.event"
|
||||
const YUEHAOXITONG_HISTORY = "web.team.yuehaoxitong.history"
|
||||
const YUEHAOXITONG_MARKET = "web.team.yuehaoxitong.market"
|
||||
@ -76,6 +92,7 @@ const YUEHAOXITONG_MESSAGE = "web.team.yuehaoxitong.message"
|
||||
const YUEHAOXITONG_NOTICE = "web.team.yuehaoxitong.notice"
|
||||
const YUEHAOXITONG_OPEN = "web.team.yuehaoxitong.open"
|
||||
const YUEHAOXITONG_PAYMENTLIST = "web.team.yuehaoxitong.paymentlist"
|
||||
const YUEHAOXITONG_PHOTO = "web.team.yuehaoxitong.photo"
|
||||
const YUEHAOXITONG_PLAN = "web.team.yuehaoxitong.plan"
|
||||
const YUEHAOXITONG_QRCODE = "web.team.yuehaoxitong.qrcode"
|
||||
const YUEHAOXITONG_RECENT = "web.team.yuehaoxitong.recent"
|
||||
|
@ -3,6 +3,7 @@ package api
|
||||
const JIAOCAIZILIAO_PORTAL = "web.team.jiaocaiziliao.portal"
|
||||
const JIAOCAIZILIAO_ALLOW = "web.team.jiaocaiziliao.allow"
|
||||
const JIAOCAIZILIAO_APPLY = "web.team.jiaocaiziliao.apply"
|
||||
const JIAOCAIZILIAO_CONTRACT = "web.team.jiaocaiziliao.contract"
|
||||
const JIAOCAIZILIAO_CREDIT = "web.team.jiaocaiziliao.credit"
|
||||
const JIAOCAIZILIAO_DOCUMENT = "web.team.jiaocaiziliao.document"
|
||||
const JIAOCAIZILIAO_EVENT = "web.team.jiaocaiziliao.event"
|
||||
@ -12,6 +13,8 @@ const JIAOCAIZILIAO_MEMBER = "web.team.jiaocaiziliao.member"
|
||||
const JIAOCAIZILIAO_MESSAGE = "web.team.jiaocaiziliao.message"
|
||||
const JIAOCAIZILIAO_NOTICE = "web.team.jiaocaiziliao.notice"
|
||||
const JIAOCAIZILIAO_OFFICIAL = "web.team.jiaocaiziliao.official"
|
||||
const JIAOCAIZILIAO_PAYMENTLIST = "web.team.jiaocaiziliao.paymentlist"
|
||||
const JIAOCAIZILIAO_PHOTO = "web.team.jiaocaiziliao.photo"
|
||||
const JIAOCAIZILIAO_QRCODE = "web.team.jiaocaiziliao.qrcode"
|
||||
const JIAOCAIZILIAO_RECENT = "web.team.jiaocaiziliao.recent"
|
||||
const JIAOCAIZILIAO_SERVICE = "web.team.jiaocaiziliao.service"
|
||||
@ -20,7 +23,9 @@ const JIAOCAIZILIAO_SUPPORT = "web.team.jiaocaiziliao.support"
|
||||
const JIAOWUXITONG_PORTAL = "web.team.jiaowuxitong.portal"
|
||||
const JIAOWUXITONG_ALLOW = "web.team.jiaowuxitong.allow"
|
||||
const JIAOWUXITONG_APPLY = "web.team.jiaowuxitong.apply"
|
||||
const JIAOWUXITONG_CONTRACT = "web.team.jiaowuxitong.contract"
|
||||
const JIAOWUXITONG_CREDIT = "web.team.jiaowuxitong.credit"
|
||||
const JIAOWUXITONG_DOCUMENT = "web.team.jiaowuxitong.document"
|
||||
const JIAOWUXITONG_EVENT = "web.team.jiaowuxitong.event"
|
||||
const JIAOWUXITONG_HOMEWORK = "web.team.jiaowuxitong.homework"
|
||||
const JIAOWUXITONG_MARKET = "web.team.jiaowuxitong.market"
|
||||
@ -28,6 +33,8 @@ const JIAOWUXITONG_MEETING = "web.team.jiaowuxitong.meeting"
|
||||
const JIAOWUXITONG_MEMBER = "web.team.jiaowuxitong.member"
|
||||
const JIAOWUXITONG_MESSAGE = "web.team.jiaowuxitong.message"
|
||||
const JIAOWUXITONG_NOTICE = "web.team.jiaowuxitong.notice"
|
||||
const JIAOWUXITONG_PAYMENTLIST = "web.team.jiaowuxitong.paymentlist"
|
||||
const JIAOWUXITONG_PHOTO = "web.team.jiaowuxitong.photo"
|
||||
const JIAOWUXITONG_QRCODE = "web.team.jiaowuxitong.qrcode"
|
||||
const JIAOWUXITONG_RECENT = "web.team.jiaowuxitong.recent"
|
||||
const JIAOWUXITONG_SERVICE = "web.team.jiaowuxitong.service"
|
||||
@ -36,12 +43,17 @@ const JIAOWUXITONG_SUPPORT = "web.team.jiaowuxitong.support"
|
||||
const KAOSHIXITONG_PORTAL = "web.team.kaoshixitong.portal"
|
||||
const KAOSHIXITONG_ALLOW = "web.team.kaoshixitong.allow"
|
||||
const KAOSHIXITONG_APPLY = "web.team.kaoshixitong.apply"
|
||||
const KAOSHIXITONG_CONTRACT = "web.team.kaoshixitong.contract"
|
||||
const KAOSHIXITONG_CREDIT = "web.team.kaoshixitong.credit"
|
||||
const KAOSHIXITONG_DOCUMENT = "web.team.kaoshixitong.document"
|
||||
const KAOSHIXITONG_EVENT = "web.team.kaoshixitong.event"
|
||||
const KAOSHIXITONG_MARKET = "web.team.kaoshixitong.market"
|
||||
const KAOSHIXITONG_MEETING = "web.team.kaoshixitong.meeting"
|
||||
const KAOSHIXITONG_MEMBER = "web.team.kaoshixitong.member"
|
||||
const KAOSHIXITONG_MESSAGE = "web.team.kaoshixitong.message"
|
||||
const KAOSHIXITONG_NOTICE = "web.team.kaoshixitong.notice"
|
||||
const KAOSHIXITONG_PAYMENTLIST = "web.team.kaoshixitong.paymentlist"
|
||||
const KAOSHIXITONG_PHOTO = "web.team.kaoshixitong.photo"
|
||||
const KAOSHIXITONG_QRCODE = "web.team.kaoshixitong.qrcode"
|
||||
const KAOSHIXITONG_QUESTION = "web.team.kaoshixitong.question"
|
||||
const KAOSHIXITONG_RECENT = "web.team.kaoshixitong.recent"
|
||||
@ -51,7 +63,9 @@ const KAOSHIXITONG_SUPPORT = "web.team.kaoshixitong.support"
|
||||
const ZAIXIANKETANG_PORTAL = "web.team.zaixianketang.portal"
|
||||
const ZAIXIANKETANG_ALLOW = "web.team.zaixianketang.allow"
|
||||
const ZAIXIANKETANG_APPLY = "web.team.zaixianketang.apply"
|
||||
const ZAIXIANKETANG_CONTRACT = "web.team.zaixianketang.contract"
|
||||
const ZAIXIANKETANG_CREDIT = "web.team.zaixianketang.credit"
|
||||
const ZAIXIANKETANG_DOCUMENT = "web.team.zaixianketang.document"
|
||||
const ZAIXIANKETANG_EVENT = "web.team.zaixianketang.event"
|
||||
const ZAIXIANKETANG_LESSON = "web.team.zaixianketang.lesson"
|
||||
const ZAIXIANKETANG_MARKET = "web.team.zaixianketang.market"
|
||||
@ -59,6 +73,8 @@ const ZAIXIANKETANG_MEETING = "web.team.zaixianketang.meeting"
|
||||
const ZAIXIANKETANG_MEMBER = "web.team.zaixianketang.member"
|
||||
const ZAIXIANKETANG_MESSAGE = "web.team.zaixianketang.message"
|
||||
const ZAIXIANKETANG_NOTICE = "web.team.zaixianketang.notice"
|
||||
const ZAIXIANKETANG_PAYMENTLIST = "web.team.zaixianketang.paymentlist"
|
||||
const ZAIXIANKETANG_PHOTO = "web.team.zaixianketang.photo"
|
||||
const ZAIXIANKETANG_QRCODE = "web.team.zaixianketang.qrcode"
|
||||
const ZAIXIANKETANG_RECENT = "web.team.zaixianketang.recent"
|
||||
const ZAIXIANKETANG_SERVICE = "web.team.zaixianketang.service"
|
||||
|
@ -4,7 +4,9 @@ const GONGYINGLIAN_PORTAL = "web.team.gongyinglian.portal"
|
||||
const GONGYINGLIAN_ALLOW = "web.team.gongyinglian.allow"
|
||||
const GONGYINGLIAN_APPLY = "web.team.gongyinglian.apply"
|
||||
const GONGYINGLIAN_BRAND = "web.team.gongyinglian.brand"
|
||||
const GONGYINGLIAN_CONTRACT = "web.team.gongyinglian.contract"
|
||||
const GONGYINGLIAN_CREDIT = "web.team.gongyinglian.credit"
|
||||
const GONGYINGLIAN_DOCUMENT = "web.team.gongyinglian.document"
|
||||
const GONGYINGLIAN_EVENT = "web.team.gongyinglian.event"
|
||||
const GONGYINGLIAN_EXPENSE = "web.team.gongyinglian.expense"
|
||||
const GONGYINGLIAN_EXPRESS = "web.team.gongyinglian.express"
|
||||
@ -18,6 +20,8 @@ const GONGYINGLIAN_MESSAGE = "web.team.gongyinglian.message"
|
||||
const GONGYINGLIAN_NOTICE = "web.team.gongyinglian.notice"
|
||||
const GONGYINGLIAN_ORDER = "web.team.gongyinglian.order"
|
||||
const GONGYINGLIAN_PAYMENT = "web.team.gongyinglian.payment"
|
||||
const GONGYINGLIAN_PAYMENTLIST = "web.team.gongyinglian.paymentlist"
|
||||
const GONGYINGLIAN_PHOTO = "web.team.gongyinglian.photo"
|
||||
const GONGYINGLIAN_PRODUCE = "web.team.gongyinglian.produce"
|
||||
const GONGYINGLIAN_PRODUCT = "web.team.gongyinglian.product"
|
||||
const GONGYINGLIAN_PURCHASE = "web.team.gongyinglian.purchase"
|
||||
@ -36,6 +40,7 @@ const GUANLIXITONG_PORTAL = "web.team.guanlixitong.portal"
|
||||
const GUANLIXITONG_ALLOW = "web.team.guanlixitong.allow"
|
||||
const GUANLIXITONG_APPLY = "web.team.guanlixitong.apply"
|
||||
const GUANLIXITONG_CONFERENCE = "web.team.guanlixitong.conference"
|
||||
const GUANLIXITONG_CONTRACT = "web.team.guanlixitong.contract"
|
||||
const GUANLIXITONG_CREDIT = "web.team.guanlixitong.credit"
|
||||
const GUANLIXITONG_DOCUMENT = "web.team.guanlixitong.document"
|
||||
const GUANLIXITONG_EMPLOYEE = "web.team.guanlixitong.employee"
|
||||
@ -48,6 +53,8 @@ const GUANLIXITONG_MEETING = "web.team.guanlixitong.meeting"
|
||||
const GUANLIXITONG_MEMBER = "web.team.guanlixitong.member"
|
||||
const GUANLIXITONG_MESSAGE = "web.team.guanlixitong.message"
|
||||
const GUANLIXITONG_NOTICE = "web.team.guanlixitong.notice"
|
||||
const GUANLIXITONG_PAYMENTLIST = "web.team.guanlixitong.paymentlist"
|
||||
const GUANLIXITONG_PHOTO = "web.team.guanlixitong.photo"
|
||||
const GUANLIXITONG_PROCUREMENT = "web.team.guanlixitong.procurement"
|
||||
const GUANLIXITONG_QRCODE = "web.team.guanlixitong.qrcode"
|
||||
const GUANLIXITONG_RECENT = "web.team.guanlixitong.recent"
|
||||
@ -60,13 +67,17 @@ const GUANLIXITONG_TARGET = "web.team.guanlixitong.target"
|
||||
const SHICHANGYINGXIAO_PORTAL = "web.team.shichangyingxiao.portal"
|
||||
const SHICHANGYINGXIAO_ALLOW = "web.team.shichangyingxiao.allow"
|
||||
const SHICHANGYINGXIAO_APPLY = "web.team.shichangyingxiao.apply"
|
||||
const SHICHANGYINGXIAO_CONTRACT = "web.team.shichangyingxiao.contract"
|
||||
const SHICHANGYINGXIAO_CREDIT = "web.team.shichangyingxiao.credit"
|
||||
const SHICHANGYINGXIAO_DOCUMENT = "web.team.shichangyingxiao.document"
|
||||
const SHICHANGYINGXIAO_EVENT = "web.team.shichangyingxiao.event"
|
||||
const SHICHANGYINGXIAO_MARKET = "web.team.shichangyingxiao.market"
|
||||
const SHICHANGYINGXIAO_MEETING = "web.team.shichangyingxiao.meeting"
|
||||
const SHICHANGYINGXIAO_MEMBER = "web.team.shichangyingxiao.member"
|
||||
const SHICHANGYINGXIAO_MESSAGE = "web.team.shichangyingxiao.message"
|
||||
const SHICHANGYINGXIAO_NOTICE = "web.team.shichangyingxiao.notice"
|
||||
const SHICHANGYINGXIAO_PAYMENTLIST = "web.team.shichangyingxiao.paymentlist"
|
||||
const SHICHANGYINGXIAO_PHOTO = "web.team.shichangyingxiao.photo"
|
||||
const SHICHANGYINGXIAO_PROMOTION = "web.team.shichangyingxiao.promotion"
|
||||
const SHICHANGYINGXIAO_QRCODE = "web.team.shichangyingxiao.qrcode"
|
||||
const SHICHANGYINGXIAO_RECENT = "web.team.shichangyingxiao.recent"
|
||||
@ -76,7 +87,9 @@ const SHICHANGYINGXIAO_SUPPORT = "web.team.shichangyingxiao.support"
|
||||
const ZIJINLIAN_PORTAL = "web.team.zijinlian.portal"
|
||||
const ZIJINLIAN_ALLOW = "web.team.zijinlian.allow"
|
||||
const ZIJINLIAN_APPLY = "web.team.zijinlian.apply"
|
||||
const ZIJINLIAN_CONTRACT = "web.team.zijinlian.contract"
|
||||
const ZIJINLIAN_CREDIT = "web.team.zijinlian.credit"
|
||||
const ZIJINLIAN_DOCUMENT = "web.team.zijinlian.document"
|
||||
const ZIJINLIAN_EVENT = "web.team.zijinlian.event"
|
||||
const ZIJINLIAN_INVESTMENT = "web.team.zijinlian.investment"
|
||||
const ZIJINLIAN_MARKET = "web.team.zijinlian.market"
|
||||
@ -84,6 +97,8 @@ const ZIJINLIAN_MEETING = "web.team.zijinlian.meeting"
|
||||
const ZIJINLIAN_MEMBER = "web.team.zijinlian.member"
|
||||
const ZIJINLIAN_MESSAGE = "web.team.zijinlian.message"
|
||||
const ZIJINLIAN_NOTICE = "web.team.zijinlian.notice"
|
||||
const ZIJINLIAN_PAYMENTLIST = "web.team.zijinlian.paymentlist"
|
||||
const ZIJINLIAN_PHOTO = "web.team.zijinlian.photo"
|
||||
const ZIJINLIAN_QRCODE = "web.team.zijinlian.qrcode"
|
||||
const ZIJINLIAN_RECENT = "web.team.zijinlian.recent"
|
||||
const ZIJINLIAN_SERVICE = "web.team.zijinlian.service"
|
||||
|
@ -3,6 +3,7 @@ package api
|
||||
const DASHBOARD_PORTAL = "web.team.dashboard.portal"
|
||||
const DASHBOARD_ALLOW = "web.team.dashboard.allow"
|
||||
const DASHBOARD_APPLY = "web.team.dashboard.apply"
|
||||
const DASHBOARD_CONTRACT = "web.team.dashboard.contract"
|
||||
const DASHBOARD_CREDIT = "web.team.dashboard.credit"
|
||||
const DASHBOARD_DASHBOARD = "web.team.dashboard.dashboard"
|
||||
const DASHBOARD_EVENT = "web.team.dashboard.event"
|
||||
@ -11,6 +12,8 @@ const DASHBOARD_MEETING = "web.team.dashboard.meeting"
|
||||
const DASHBOARD_MEMBER = "web.team.dashboard.member"
|
||||
const DASHBOARD_MESSAGE = "web.team.dashboard.message"
|
||||
const DASHBOARD_NOTICE = "web.team.dashboard.notice"
|
||||
const DASHBOARD_PAYMENTLIST = "web.team.dashboard.paymentlist"
|
||||
const DASHBOARD_PHOTO = "web.team.dashboard.photo"
|
||||
const DASHBOARD_QRCODE = "web.team.dashboard.qrcode"
|
||||
const DASHBOARD_RECENT = "web.team.dashboard.recent"
|
||||
const DASHBOARD_SERVICE = "web.team.dashboard.service"
|
||||
@ -19,62 +22,3 @@ const DASHBOARD_SUMMARY = "web.team.dashboard.summary"
|
||||
const DASHBOARD_SUPPORT = "web.team.dashboard.support"
|
||||
const DEVELOPMENT_PORTAL = "web.team.development.portal"
|
||||
const DEVELOPMENT_ALLOW = "web.team.development.allow"
|
||||
const DEVELOPMENT_APPLY = "web.team.development.apply"
|
||||
const DEVELOPMENT_CREDIT = "web.team.development.credit"
|
||||
const DEVELOPMENT_EVENT = "web.team.development.event"
|
||||
const DEVELOPMENT_HISTORY = "web.team.development.history"
|
||||
const DEVELOPMENT_MARKET = "web.team.development.market"
|
||||
const DEVELOPMENT_MEETING = "web.team.development.meeting"
|
||||
const DEVELOPMENT_MEMBER = "web.team.development.member"
|
||||
const DEVELOPMENT_MESSAGE = "web.team.development.message"
|
||||
const DEVELOPMENT_NOTICE = "web.team.development.notice"
|
||||
const DEVELOPMENT_QRCODE = "web.team.development.qrcode"
|
||||
const DEVELOPMENT_RECENT = "web.team.development.recent"
|
||||
const DEVELOPMENT_SERVE = "web.team.development.serve"
|
||||
const DEVELOPMENT_SERVICE = "web.team.development.service"
|
||||
const DEVELOPMENT_SETTING = "web.team.development.setting"
|
||||
const DEVELOPMENT_SUPPORT = "web.team.development.support"
|
||||
const DEVELOPMENT_VERSION = "web.team.development.version"
|
||||
const OPERATION_PORTAL = "web.team.operation.portal"
|
||||
const OPERATION_ALLOW = "web.team.operation.allow"
|
||||
const OPERATION_APPLY = "web.team.operation.apply"
|
||||
const OPERATION_CREDIT = "web.team.operation.credit"
|
||||
const OPERATION_EVENT = "web.team.operation.event"
|
||||
const OPERATION_MARKET = "web.team.operation.market"
|
||||
const OPERATION_MEETING = "web.team.operation.meeting"
|
||||
const OPERATION_MEMBER = "web.team.operation.member"
|
||||
const OPERATION_MESSAGE = "web.team.operation.message"
|
||||
const OPERATION_NOTICE = "web.team.operation.notice"
|
||||
const OPERATION_QRCODE = "web.team.operation.qrcode"
|
||||
const OPERATION_RECENT = "web.team.operation.recent"
|
||||
const OPERATION_RELEASE = "web.team.operation.release"
|
||||
const OPERATION_SERVICE = "web.team.operation.service"
|
||||
const OPERATION_SETTING = "web.team.operation.setting"
|
||||
const OPERATION_SUPPORT = "web.team.operation.support"
|
||||
const PRODUCTION_PORTAL = "web.team.production.portal"
|
||||
const PRODUCTION_ALLOW = "web.team.production.allow"
|
||||
const PRODUCTION_APPLY = "web.team.production.apply"
|
||||
const PRODUCTION_CASE = "web.team.production.case"
|
||||
const PRODUCTION_CREDIT = "web.team.production.credit"
|
||||
const PRODUCTION_EVENT = "web.team.production.event"
|
||||
const PRODUCTION_ISSUE = "web.team.production.issue"
|
||||
const PRODUCTION_MARKET = "web.team.production.market"
|
||||
const PRODUCTION_MEETING = "web.team.production.meeting"
|
||||
const PRODUCTION_MEMBER = "web.team.production.member"
|
||||
const PRODUCTION_MESSAGE = "web.team.production.message"
|
||||
const PRODUCTION_NOTICE = "web.team.production.notice"
|
||||
const PRODUCTION_PLAN = "web.team.production.plan"
|
||||
const PRODUCTION_QRCODE = "web.team.production.qrcode"
|
||||
const PRODUCTION_RECENT = "web.team.production.recent"
|
||||
const PRODUCTION_SERVICE = "web.team.production.service"
|
||||
const PRODUCTION_SETTING = "web.team.production.setting"
|
||||
const PRODUCTION_SUPPORT = "web.team.production.support"
|
||||
const PRODUCTION_TASK = "web.team.production.task"
|
||||
const STORAGE_PORTAL = "web.team.storage.portal"
|
||||
const STORAGE_ALLOW = "web.team.storage.allow"
|
||||
const STORAGE_APPLY = "web.team.storage.apply"
|
||||
const STORAGE_CREDIT = "web.team.storage.credit"
|
||||
const STORAGE_EVENT = "web.team.storage.event"
|
||||
const STORAGE_FILE = "web.team.storage.file"
|
||||
const STORAGE_MARKET = "web.team.storage.market"
|
||||
const STORAGE_MEETING = "web.team.storage.meeting"
|
||||
|
@ -367,6 +367,23 @@ func (s Table) AuthCreate(m *ice.Message, authType int, fromUID string, arg ...s
|
||||
)
|
||||
s.Update(m, kit.Dict(m.OptionSimple(model.AUTH_UID)), arg...)
|
||||
}
|
||||
func (s Table) PlaceIsAuthed(m *ice.Message, arg ...string) *ice.Message {
|
||||
if msg := m.Cmd(s.Place, s.Select, model.UID, arg[0]); msg.Append(model.AUTH_UID) == "" {
|
||||
m.Echo("本服务暂未申请认证,请到<用户名片>申请认证")
|
||||
return nil
|
||||
} else if m.Cmd(api.RENZHENGSHOUQUAN_AUTH, s.Select, model.UID, msg.Append(model.AUTH_UID)).Append(model.AUTH_STATUS) != "2" {
|
||||
m.Echo("本服务认证申请中,请等待审批")
|
||||
return nil
|
||||
} else {
|
||||
return msg
|
||||
}
|
||||
}
|
||||
func (s Table) StreetAuthUID(m *ice.Message, arg ...string) string {
|
||||
if msg := s.PlaceIsAuthed(m, arg...); msg != nil {
|
||||
return m.Cmd(s.Street, s.Select, model.UID, msg.Append(s.STREET_UID)).Append(model.AUTH_UID)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
func (s Table) DashboardUpdate(m *ice.Message, arg ...string) {
|
||||
if m.IsErr() {
|
||||
return
|
||||
|
@ -1,28 +1,53 @@
|
||||
package gonganxitong
|
||||
|
||||
import "shylinux.com/x/ice"
|
||||
import (
|
||||
"shylinux.com/x/ice"
|
||||
|
||||
"shylinux.com/x/community/src/api"
|
||||
"shylinux.com/x/community/src/gonganxitong/model"
|
||||
)
|
||||
|
||||
type document struct {
|
||||
Table
|
||||
order string `data:"93"`
|
||||
fields string `data:"user_uid"`
|
||||
fields string `data:"folder_id,vendor,user_uid"`
|
||||
open string `name:"open" style:"notice" role:"void"`
|
||||
}
|
||||
|
||||
func (s document) List(m *ice.Message, arg ...string) {
|
||||
m.Action(s.Auth)
|
||||
func (s document) Config(m *ice.Message, arg ...string) {
|
||||
s.InsertOrUpdate(m, arg, m.OptionSimple(model.PLACE_UID)...)
|
||||
}
|
||||
func (s document) Auth(m *ice.Message, arg ...string) {
|
||||
if m.Option("code") == "" {
|
||||
m.Cmdy(DocumentVendor, DocumentVendor.AuthLink, m.PrefixKey()+"/action/auth", m.Option(s.PLACE_UID))
|
||||
} else {
|
||||
m.Cmdy(DocumentVendor, DocumentVendor.GetToken)
|
||||
}
|
||||
func (s document) List(m *ice.Message, arg ...string) {
|
||||
s.cmdy(m, DocumentVendor.Folder).PushAction(s.Open).Display("")
|
||||
}
|
||||
func (s document) Open(m *ice.Message, arg ...string) {
|
||||
m.ProcessOpen(m.Option(model.LINK))
|
||||
}
|
||||
|
||||
func init() { ice.TeamCtxCmd(document{Table: newTable()}) }
|
||||
|
||||
var DocumentVendor interface {
|
||||
AuthLink(m *ice.Message, arg ...string)
|
||||
GetToken(m *ice.Message, arg ...string)
|
||||
GetList(m *ice.Message, arg ...string)
|
||||
func (s document) cmdy(m *ice.Message, action ice.Any, arg ...string) *ice.Message {
|
||||
if m.Option(model.AUTH_UID, s.authUID(m, m.Option(s.PLACE_UID))) == "" {
|
||||
return m
|
||||
}
|
||||
if msg := s.Select(m.Spawn(), model.PLACE_UID, m.Option(s.PLACE_UID)); msg.Append("folder_id") == "" {
|
||||
m.Echo("本服务暂未配置,请联系公司管理员配置")
|
||||
} else {
|
||||
m.Cmdy(msg.Append(model.VENDOR), action, m.Option(model.AUTH_UID), msg.Append("folder_id"))
|
||||
}
|
||||
return m
|
||||
}
|
||||
func (s document) authUID(m *ice.Message, arg ...string) string {
|
||||
if msg := m.Cmd(s.Place, s.Select, model.UID, arg[0]); msg.Append(model.AUTH_UID) == "" {
|
||||
m.Echo("本服务暂未申请认证,请到<用户名片>申请认证")
|
||||
} else if m.Cmd(api.RENZHENGSHOUQUAN_AUTH, s.Select, model.UID, msg.Append(model.AUTH_UID)).Append(model.AUTH_STATUS) != "2" {
|
||||
m.Echo("本服务认证申请中,请等待审批")
|
||||
} else {
|
||||
return m.Cmd(s.Street, s.Select, model.UID, msg.Append(s.STREET_UID)).Append(model.AUTH_UID)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var DocumentVendor interface {
|
||||
Folder(m *ice.Message, arg ...string) *ice.Message
|
||||
}
|
||||
|
8
src/gonganxitong/document.js
Normal file
8
src/gonganxitong/document.js
Normal file
@ -0,0 +1,8 @@
|
||||
Volcanos(chat.ONIMPORT, {
|
||||
_init: function(can, msg) {
|
||||
can.onimport.myView(can, msg, function(value) { return [
|
||||
{view: html.TITLE, list: [value.name+"."+value.type, can.onimport.titleAction(can, value)]},
|
||||
{view: html.STATUS, list: [value.ownerName, can.onimport.timeView(can, value)]},
|
||||
] })
|
||||
},
|
||||
})
|
@ -109,6 +109,8 @@ const (
|
||||
UNIT = "unit"
|
||||
LINK = "link"
|
||||
AMOUNT = "amount"
|
||||
ACCESS_TOKEN = "access_token"
|
||||
EXPIRE_TIME = "expire_time"
|
||||
)
|
||||
|
||||
type Sess struct {
|
||||
@ -182,9 +184,19 @@ type Paymentlist struct {
|
||||
}
|
||||
type Photo struct {
|
||||
db.ModelWithUID
|
||||
PlaceUID string `gorm:"type:char(32);index"`
|
||||
UserUID string `gorm:"type:char(32);index"`
|
||||
SpaceID string `gorm:"type:varchar(128)"`
|
||||
AccessToken string `gorm:"type:varchar(512)"`
|
||||
ExpireTime db.Time
|
||||
Vendor string `gorm:"type:varchar(128)"`
|
||||
}
|
||||
type Document struct {
|
||||
db.ModelWithUID
|
||||
PlaceUID string `gorm:"type:char(32);index"`
|
||||
UserUID string `gorm:"type:char(32);index"`
|
||||
FolderID string `gorm:"type:varchar(128)"`
|
||||
Vendor string `gorm:"type:varchar(128)"`
|
||||
}
|
||||
type Contract struct {
|
||||
db.ModelWithUID
|
||||
|
@ -1,17 +1,52 @@
|
||||
package gonganxitong
|
||||
|
||||
import "shylinux.com/x/ice"
|
||||
import (
|
||||
"shylinux.com/x/ice"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
|
||||
"shylinux.com/x/community/src/gonganxitong/model"
|
||||
)
|
||||
|
||||
type photo struct {
|
||||
Table
|
||||
order string `data:"95"`
|
||||
fields string `data:"title,content,user_uid"`
|
||||
create string `name:"create title* content*" role:"leader"`
|
||||
remove string `name:"remove" role:"leader"`
|
||||
fields string `data:"space_id,access_token,expire_time,vendor"`
|
||||
remove string `name:"remove" role:"worker"`
|
||||
upload string `name:"upload" role:"worker"`
|
||||
trash string `name:"trash" role:"worker"`
|
||||
}
|
||||
|
||||
func (s photo) List(m *ice.Message, arg ...string) {
|
||||
m.Echo("功能正在开发中,敬请等待。")
|
||||
func (s photo) Config(m *ice.Message, arg ...string) {
|
||||
s.InsertOrUpdate(m, arg, m.OptionSimple(model.PLACE_UID)...)
|
||||
}
|
||||
func (s photo) List(m *ice.Message, arg ...string) {
|
||||
s.cmdy(m, PhotoVendor.Folder, kit.Slice(arg, 1)...)
|
||||
m.PushAction(s.Trash).Action(s.Upload).Display("")
|
||||
s.Button(m, "请上传文件", s.Upload)
|
||||
}
|
||||
func (s photo) Upload(m *ice.Message, arg ...string) { s.cmdy(m, "") }
|
||||
func (s photo) Trash(m *ice.Message, arg ...string) { s.cmdy(m, "") }
|
||||
|
||||
func init() { ice.TeamCtxCmd(photo{Table: newTable()}) }
|
||||
|
||||
func (s photo) cmdy(m *ice.Message, action ice.Any, arg ...string) {
|
||||
const SPACE_ID = "space_id"
|
||||
if m.Option(model.AUTH_UID, s.StreetAuthUID(m, m.Option(s.PLACE_UID))) == "" {
|
||||
return
|
||||
}
|
||||
if msg := s.Select(m.Spawn(), model.PLACE_UID, m.Option(s.PLACE_UID)); msg.Append(SPACE_ID) == "" {
|
||||
m.Echo("本服务暂未配置,请联系公司管理员配置")
|
||||
} else {
|
||||
kit.If(action == "", func() { action = m.ActionKey() })
|
||||
m.Option(model.PLACE_UID, m.Option(s.PLACE_UID))
|
||||
_msg := m.Cmd(msg.Append(model.VENDOR), PhotoVendor.Token, msg.Append(SPACE_ID), msg.Append(model.ACCESS_TOKEN), msg.Append(model.EXPIRE_TIME))
|
||||
m.Cmdy(msg.Append(model.VENDOR), action, m.Option(model.AUTH_UID), msg.Append(SPACE_ID), _msg.Append(model.ACCESS_TOKEN), arg)
|
||||
}
|
||||
}
|
||||
|
||||
var PhotoVendor interface {
|
||||
Folder(m *ice.Message, arg ...string)
|
||||
Upload(m *ice.Message, arg ...string)
|
||||
Trash(m *ice.Message, arg ...string)
|
||||
Token(m *ice.Message, arg ...string)
|
||||
}
|
||||
|
8
src/gonganxitong/photo.js
Normal file
8
src/gonganxitong/photo.js
Normal file
@ -0,0 +1,8 @@
|
||||
Volcanos(chat.ONIMPORT, {
|
||||
_init: function(can, msg) {
|
||||
can.onimport.myView(can, msg, function(value) { return [
|
||||
{view: html.TITLE, list: [value.name]},
|
||||
{view: html.STATUS, list: [can.base.Size(value.size), can.base.TimeTrim(value.modify_time)]},
|
||||
] })
|
||||
},
|
||||
})
|
@ -303,11 +303,11 @@ func (s Portal) DashboardUpdate(m *ice.Message, arg ...string) {
|
||||
}
|
||||
func (s Portal) StorageCreate(m *ice.Message, name string, arg ...string) {
|
||||
kit.If(name == "", func() { name = m.Option(s.Keys(s.Place, model.NAME)) })
|
||||
s.AutoCmdy(m, api.STORAGE_PORTAL, s.PlaceCreate, m.OptionSimple(model.CITY_NAME, model.COMPANY_NAME), model.STORAGE_NAME, name, model.STORAGE_TYPE, "0")
|
||||
// s.AutoCmdy(m, api.STORAGE_PORTAL, s.PlaceCreate, m.OptionSimple(model.CITY_NAME, model.COMPANY_NAME), model.STORAGE_NAME, name, model.STORAGE_TYPE, "0")
|
||||
s.AutoCmd(m, api.RENZHENGSHOUQUAN_AUTH, s.UpdateField, m.OptionSimple(model.STORAGE_UID))
|
||||
}
|
||||
func (s Portal) StorageInsert(m *ice.Message, title, content string) {
|
||||
s.AutoCmd(m, api.STORAGE_FILE, s.Insert, model.TITLE, title, model.CONTENT, content, m.OptionSimple(model.STORAGE_UID, model.USER_UID))
|
||||
// s.AutoCmd(m, api.STORAGE_FILE, s.Insert, model.TITLE, title, model.CONTENT, content, m.OptionSimple(model.STORAGE_UID, model.USER_UID))
|
||||
}
|
||||
func (s Table) NoticeList(m *ice.Message, arg ...string) {
|
||||
s.Limit(m, 1)
|
||||
|
@ -34,6 +34,8 @@ func (s Table) Inputs(m *ice.Message, arg ...string) {
|
||||
s.Table.Inputs(m, arg...)
|
||||
}
|
||||
}
|
||||
func (s Table) Config(m *ice.Message, arg ...string) {
|
||||
}
|
||||
func (s Table) RewriteAppend(m *ice.Message, arg ...string) *ice.Message {
|
||||
m.RewriteAppend(func(value, key string, index int) string {
|
||||
if _, e := strconv.ParseInt(value, 10, 64); e != nil {
|
||||
|
@ -3,10 +3,21 @@ package model
|
||||
import "shylinux.com/x/mysql-story/src/db"
|
||||
|
||||
const (
|
||||
UID = "uid"
|
||||
NAME = "name"
|
||||
INFO = "info"
|
||||
PLACE_UID = "place_uid"
|
||||
USER_UID = "user_uid"
|
||||
AUTH_UID = "auth_uid"
|
||||
AUTH_STATUS = "auth_status"
|
||||
PHOTO_UID = "photo_uid"
|
||||
VENDOR = "vendor"
|
||||
LIBRARY_ID = "library_id"
|
||||
LIBRARY_SECRET = "library_secret"
|
||||
ACCESS_TOKEN = "access_token"
|
||||
EXPIRE_TIME = "expire_time"
|
||||
SPACE_ID = "space_id"
|
||||
USER_ID = "user_id"
|
||||
)
|
||||
|
||||
type Smh struct {
|
||||
@ -17,6 +28,8 @@ type Smh struct {
|
||||
Info string `gorm:"type:varchar(64)"`
|
||||
LibraryID string `gorm:"type:varchar(32)"`
|
||||
LibrarySecret string `gorm:"type:varchar(64)"`
|
||||
AccessToken string `gorm:"type:varchar(512)"`
|
||||
ExpireTime db.Time
|
||||
}
|
||||
|
||||
func init() { db.CmdModels("", &Smh{}) }
|
||||
|
@ -2,34 +2,48 @@ package smh
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"shylinux.com/x/ice"
|
||||
"shylinux.com/x/icebergs/base/mdb"
|
||||
"shylinux.com/x/icebergs/base/nfs"
|
||||
"shylinux.com/x/icebergs/base/web"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
|
||||
"shylinux.com/x/community/src/api"
|
||||
"shylinux.com/x/community/src/gonganxitong"
|
||||
"shylinux.com/x/community/src/renzhengshouquan"
|
||||
"shylinux.com/x/community/src/renzhengshouquan/external/tencentcloud"
|
||||
"shylinux.com/x/community/src/renzhengshouquan/external/tencentcloud/smh/model"
|
||||
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
|
||||
sdk "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/smh/v20210712"
|
||||
)
|
||||
|
||||
type smh struct {
|
||||
renzhengshouquan.Table
|
||||
tencentcloud.Tencentcloud
|
||||
order string `data:"18"`
|
||||
fields string `data:"name,info,user_uid"`
|
||||
create string `name:"create name* info*" role:"leader"`
|
||||
remove string `name:"remove" role:"leader"`
|
||||
order string `data:"18"`
|
||||
fields string `data:"name,info,library_id,library_secret,access_token,expire_time,user_uid"`
|
||||
libraryCreate string `name:"libraryCreate" role:"leader"`
|
||||
libraryRemove string `name:"libraryRemove" role:"leader"`
|
||||
spaceCreate string `name:"spaceCreate" role:"leader"`
|
||||
spaceRemove string `name:"spaceRemove" role:"leader"`
|
||||
}
|
||||
|
||||
func (s smh) Create(m *ice.Message, arg ...string) {
|
||||
func (s smh) Init(m *ice.Message, arg ...string) {
|
||||
s.Table.Init(m, arg...)
|
||||
m.Cmd(web.SPIDE, mdb.CREATE, "https://api.tencentsmh.cn/api/v1/", "tencentsmh")
|
||||
}
|
||||
func (s smh) LibraryCreate(m *ice.Message, arg ...string) {
|
||||
msg := m.Cmd(api.RENZHENGSHOUQUAN_AUTH, s.Select, model.UID, m.Option(model.AUTH_UID))
|
||||
request := sdk.NewCreateLibraryRequest()
|
||||
request.Name = common.StringPtr(m.Option(model.NAME))
|
||||
request.Remark = common.StringPtr(m.Option(model.INFO))
|
||||
request.Name = common.StringPtr(msg.Append(model.NAME))
|
||||
request.Remark = common.StringPtr(msg.Append(model.INFO))
|
||||
request.LibraryExtension = &sdk.LibraryExtension{
|
||||
IsFileLibrary: common.BoolPtr(false),
|
||||
IsFileLibrary: common.BoolPtr(true),
|
||||
IsMultiSpace: common.BoolPtr(true),
|
||||
IsMultiAlbum: common.BoolPtr(true),
|
||||
}
|
||||
@ -43,30 +57,138 @@ func (s smh) Create(m *ice.Message, arg ...string) {
|
||||
if m.Warn(err) {
|
||||
return
|
||||
}
|
||||
s.Table.Create(m, kit.Simple(m.OptionSimple(model.NAME, model.INFO), model.LIBRARY_ID, *res.Response.LibraryId, model.LIBRARY_SECRET, *res.Response.LibrarySecret)...)
|
||||
s.Table.Create(m, kit.Simple(msg.AppendSimple(model.NAME, model.INFO), model.LIBRARY_ID, *res.Response.LibraryId, model.LIBRARY_SECRET, *res.Response.LibrarySecret)...)
|
||||
}
|
||||
func (s smh) LibraryRemove(m *ice.Message, arg ...string) {
|
||||
request := sdk.NewDeleteLibraryRequest()
|
||||
request.LibraryId = common.StringPtr(m.Option(model.LIBRARY_ID))
|
||||
if _, err := s.newClient(m).DeleteLibrary(request); err != nil {
|
||||
if err, ok := err.(*errors.TencentCloudSDKError); ok {
|
||||
if err.Code == "ResourceInUse.MultiSpace" {
|
||||
m.Warn(true, "请先清理用户空间,清理")
|
||||
} else {
|
||||
m.Warn(true, err.Message)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
s.Table.Remove(m, arg...)
|
||||
}
|
||||
func (s smh) List(m *ice.Message, arg ...string) {
|
||||
s.ValueList(m, arg).Display("")
|
||||
return
|
||||
|
||||
req := sdk.NewDescribeLibrariesRequest()
|
||||
res, err := s.newClient(m).DescribeLibraries(req)
|
||||
m.Warn(err)
|
||||
kit.For(kit.Value(kit.UnMarshal(res.ToJsonString()), "Response.List"), func(value ice.Map) {
|
||||
m.PushRecord(value, "Name", "Remark", "LibraryId", "DirNum", "FileNum")
|
||||
if len(arg) == 1 {
|
||||
if s.ValueList(m, arg).Display("").Length() == 0 {
|
||||
s.Button(m.SetResult(), "请创建媒体库", s.LibraryCreate)
|
||||
} else {
|
||||
msg := s.token(m)
|
||||
m.Table(func(value ice.Maps) {
|
||||
_msg := s.spide(m.Spawn(), kit.MergeURL(kit.Format("usage/%s", msg.Append(model.LIBRARY_ID)), msg.AppendSimple(model.ACCESS_TOKEN)))
|
||||
m.PushRecord(kit.UnMarshal(_msg.Result()), "totalFileSize")
|
||||
}).PushAction(s.LibraryRemove).Action()
|
||||
}
|
||||
} else if len(arg) == 2 {
|
||||
m.Cmdy(api.RENZHENGSHOUQUAN_AUTH, arg[0]).Table(func(value ice.Maps) {
|
||||
if renzhengshouquan.AuthStatus(kit.Int(value[model.AUTH_STATUS])) == renzhengshouquan.AuthIssued {
|
||||
msg := s.cmdy(m.Spawn(), s.Select, model.PLACE_UID, value[model.PLACE_UID])
|
||||
if space_id := msg.Append(model.SPACE_ID); space_id == "" {
|
||||
m.Push(model.SPACE_ID, "").Push(model.PHOTO_UID, "").PushButton(s.SpaceCreate)
|
||||
} else {
|
||||
m.Push(model.SPACE_ID, msg.Append(model.SPACE_ID))
|
||||
m.Push(model.PHOTO_UID, msg.Append(model.UID))
|
||||
m.PushButton(s.SpaceRemove)
|
||||
}
|
||||
} else {
|
||||
m.Push(model.SPACE_ID, "").Push(model.PHOTO_UID, "").PushButton()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
func (s smh) SpaceCreate(m *ice.Message, arg ...string) {
|
||||
msg := s.token(m)
|
||||
if s.spide(m, http.MethodPost, kit.MergeURL(kit.Format("space/%s", msg.Append(model.LIBRARY_ID)), model.USER_ID, m.Option(model.PLACE_UID), msg.AppendSimple(model.ACCESS_TOKEN)),
|
||||
"spaceTag", m.Option(model.NAME)).IsErr() {
|
||||
return
|
||||
}
|
||||
m.Option(model.SPACE_ID, kit.Value(kit.UnMarshal(m.Result()), "spaceId"))
|
||||
s.cmdy(m, s.Config, m.OptionSimple(model.PLACE_UID, model.USER_UID, model.SPACE_ID), model.VENDOR, m.PrefixKey())
|
||||
}
|
||||
func (s smh) SpaceRemove(m *ice.Message, arg ...string) {
|
||||
msg := s.token(m)
|
||||
if s.spide(m, http.MethodDelete, kit.MergeURL(kit.Format("space/%s/%s", msg.Append(model.LIBRARY_ID), m.Option(model.SPACE_ID)), msg.AppendSimple(model.ACCESS_TOKEN))).IsErr() {
|
||||
return
|
||||
}
|
||||
s.cmdy(m.Options(model.UID, m.Option(model.PHOTO_UID)), s.Delete, m.OptionSimple(model.PLACE_UID, model.SPACE_ID), model.VENDOR, m.PrefixKey())
|
||||
}
|
||||
func (s smh) Folder(m *ice.Message, arg ...string) {
|
||||
msg := s.token(m)
|
||||
if len(arg) > 3 {
|
||||
m.EchoImages(kit.MergeURL(kit.Format("https://api.tencentsmh.cn/api/v1/file/%s/%s/%s", msg.Append(model.LIBRARY_ID), arg[1], arg[3]),
|
||||
"height_size", "320", "width_size", "320", model.ACCESS_TOKEN, arg[2])).Echo(arg[3])
|
||||
return
|
||||
}
|
||||
s.spide(m, kit.MergeURL(kit.Format("directory/%s/%s/", msg.Append(model.LIBRARY_ID), arg[1]), msg.AppendSimple(model.ACCESS_TOKEN)))
|
||||
kit.For(kit.Value(kit.UnMarshal(m.Result()), "contents"), func(value ice.Map) {
|
||||
t, _ := time.ParseInLocation("2006-01-02T15:04:05.000Z", kit.Format(value["modificationTime"]), time.UTC)
|
||||
value["modify_time"] = t.Add(time.Hour * 8).Format(ice.MOD_TIME)
|
||||
m.PushRecord(value, "name", "size", "modify_time", "type", "fileType", "contentType").Push(model.UID, value["name"])
|
||||
m.Push("icons", kit.MergeURL(kit.Format("https://api.tencentsmh.cn/api/v1/file/%s/%s/%s", msg.Append(model.LIBRARY_ID), arg[1], value["name"]),
|
||||
"height_size", "128", "width_size", "128", model.ACCESS_TOKEN, arg[2]))
|
||||
})
|
||||
m.PushAction(s.Token)
|
||||
m.Display("")
|
||||
m.SetResult()
|
||||
}
|
||||
func (s smh) Upload(m *ice.Message, arg ...string) {
|
||||
msg := s.token(m)
|
||||
up := kit.Simple(m.Optionv(ice.MSG_UPLOAD))
|
||||
_msg := m.Cmd(web.CACHE, up[0])
|
||||
if s.spide(m, http.MethodPut, kit.MergeURL(kit.Format("file/%s/%s/%s", msg.Append(model.LIBRARY_ID), arg[1], path.Base(up[1])),
|
||||
"conflict_resolution_strategy", "rename", "filesize", up[2], msg.AppendSimple(model.ACCESS_TOKEN))).IsErr() {
|
||||
return
|
||||
}
|
||||
res := kit.UnMarshal(m.Result())
|
||||
if s.spide(m.Options(web.SPIDE_HEADER, kit.Value(res, "headers")), http.MethodPut,
|
||||
"https://"+kit.Format(kit.Value(res, web.DOMAIN))+kit.Format(kit.Value(res, nfs.PATH)), web.SPIDE_FILE, _msg.Append(nfs.FILE)).IsErr() {
|
||||
return
|
||||
}
|
||||
s.spide(m, http.MethodPost, kit.MergeURL(kit.Format("file/%s/%s/%s", msg.Append(model.LIBRARY_ID), arg[1], kit.Value(res, "confirmKey")),
|
||||
"confirm", "confirm", "conflict_resolution_strategy", "rename", msg.AppendSimple(model.ACCESS_TOKEN)))
|
||||
}
|
||||
func (s smh) Trash(m *ice.Message, arg ...string) {
|
||||
msg := s.token(m)
|
||||
s.spide(m, http.MethodDelete, kit.MergeURL(kit.Format("file/%s/%s/%s", msg.Append(model.LIBRARY_ID), arg[1], m.Option(model.NAME)), msg.AppendSimple(model.ACCESS_TOKEN)))
|
||||
}
|
||||
func (s smh) Token(m *ice.Message, arg ...string) {
|
||||
m.Cmdy(web.SPIDE, ice.DEV, http.MethodGet, "https://api.tencentsmh.cn/api/v1/token",
|
||||
"library_id", "smh2xn3qy4qixh16",
|
||||
"library_secret", "42611fef1061b3f24e693d887ad5c904c9875b0199197b576015525c3317f2c0",
|
||||
)
|
||||
if arg[1] == "" || arg[2] < m.Time() {
|
||||
msg := s.token(m)
|
||||
if _msg := s.spide(m.Spawn(), "token", msg.AppendSimple(model.LIBRARY_ID, model.LIBRARY_SECRET), model.SPACE_ID, arg[0]); !_msg.IsErr() {
|
||||
res := kit.UnMarshal(_msg.Result())
|
||||
s.cmdy(m, s.Config, model.ACCESS_TOKEN, kit.Value(res, "accessToken"), model.EXPIRE_TIME, m.Time(kit.Format(kit.Value(res, "expiresIn"))+"s"))
|
||||
m.Push(model.ACCESS_TOKEN, kit.Value(res, "accessToken"))
|
||||
}
|
||||
} else {
|
||||
m.Push(model.ACCESS_TOKEN, arg[1])
|
||||
}
|
||||
}
|
||||
|
||||
func init() { ice.TeamCtxCmd(smh{}) }
|
||||
|
||||
func init() { gonganxitong.PhotoVendor = smh{} }
|
||||
|
||||
func (s smh) cmdy(m *ice.Message, arg ...ice.Any) *ice.Message {
|
||||
return m.Cmdy(append([]ice.Any{"web.team.gonganxitong.photo"}, arg...)...)
|
||||
}
|
||||
func (s smh) token(m *ice.Message, arg ...string) *ice.Message {
|
||||
msg := s.Select(m.Spawn(), m.OptionSimple(model.AUTH_UID)...)
|
||||
if msg.Append(model.ACCESS_TOKEN) == "" || msg.Append(model.EXPIRE_TIME) < m.Time() {
|
||||
if _msg := s.spide(m.Spawn(), "token", msg.AppendSimple(model.LIBRARY_ID, model.LIBRARY_SECRET), "grant", "admin"); !_msg.IsErr() {
|
||||
res := kit.UnMarshal(_msg.Result())
|
||||
s.Update(m, kit.Dict(model.ACCESS_TOKEN, kit.Value(res, "accessToken"), model.EXPIRE_TIME, m.Time(kit.Format(kit.Value(res, "expiresIn"))+"s")), m.OptionSimple(model.AUTH_UID)...)
|
||||
}
|
||||
msg = s.Select(m.Spawn(), m.OptionSimple(model.AUTH_UID)...)
|
||||
}
|
||||
return msg
|
||||
}
|
||||
func (s smh) spide(m *ice.Message, arg ...ice.Any) *ice.Message {
|
||||
return m.SetAppend().SetResult().Cmdy(append([]ice.Any{web.SPIDE, "tencentsmh", web.SPIDE_RAW}, arg...)...).Options(web.SPIDE_HEADER, kit.Dict())
|
||||
}
|
||||
func (s smh) newClient(m *ice.Message, arg ...string) *sdk.Client {
|
||||
c, _ := sdk.NewClient(s.NewCredential(m), "", s.NewProfile(m))
|
||||
return c
|
||||
|
@ -1,7 +1,8 @@
|
||||
Volcanos(chat.ONIMPORT, {
|
||||
_init: function(can, msg) {
|
||||
can.onimport.myView(can, msg, function(value) { return [
|
||||
{view: html.TITLE, list: [value.name]},
|
||||
{view: html.TITLE, list: [value.name, can.onimport.titleAction(can, value)]},
|
||||
{view: html.STATUS, list: [value.library_id, can.onimport.timeView(can, value), can.base.Size(value.totalFileSize)]},
|
||||
{view: html.OUTPUT, list: [value.info]},
|
||||
] })
|
||||
},
|
||||
|
@ -1,5 +1,15 @@
|
||||
{
|
||||
"smh": "智能媒资托管",
|
||||
"libraryCreate": "创建",
|
||||
"libraryRemove": "删除",
|
||||
"spaceCreate": "分配",
|
||||
"spaceRemove": "清理",
|
||||
"style": {
|
||||
"libraryCreate": "notice",
|
||||
"libraryRemove": "danger",
|
||||
"spaceCreate": "notice",
|
||||
"spaceRemove": "danger"
|
||||
},
|
||||
"icons": {
|
||||
"smh": "https://img.icons8.com/officel/80/stack-of-photos.png"
|
||||
},
|
||||
|
5
src/renzhengshouquan/external/tencentcloud/smh/smh.shy
vendored
Normal file
5
src/renzhengshouquan/external/tencentcloud/smh/smh.shy
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
chapter "智能媒资"
|
||||
refer `
|
||||
后台 https://console.cloud.tencent.com/smh/overview
|
||||
文档 https://cloud.tencent.com/document/product/1339
|
||||
`
|
@ -45,6 +45,13 @@ func (s Tencentcloud) ImageData(m *ice.Message, arg ...string) string {
|
||||
}
|
||||
func (s Tencentcloud) ParseResponse(m *ice.Message, res interface{ ToJsonString() string }, err error, arg ...string) {
|
||||
if !m.Warn(err) {
|
||||
m.PushDetail(kit.Value(kit.UnMarshal(res.ToJsonString()), "Response"))
|
||||
m.PushDetail(kit.Value(kit.UnMarshal(res.ToJsonString()), kit.Select("Response", arg, 0)))
|
||||
}
|
||||
}
|
||||
func (s Tencentcloud) ParseResponseList(m *ice.Message, res interface{ ToJsonString() string }, err error, arg ...string) {
|
||||
if !m.Warn(err) {
|
||||
kit.For(kit.Value(kit.UnMarshal(res.ToJsonString()), kit.Select("Response.List", arg, 0)), func(value ice.Map) {
|
||||
m.PushRecord(value, kit.Slice(arg, 1)...)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -2,12 +2,31 @@ package model
|
||||
|
||||
import "shylinux.com/x/mysql-story/src/db"
|
||||
|
||||
const (
|
||||
NAME = "name"
|
||||
LINK = "link"
|
||||
VENDOR = "vendor"
|
||||
USER_UID = "user_uid"
|
||||
PLACE_UID = "place_uid"
|
||||
AUTH_UID = "auth_uid"
|
||||
AUTH_STATUS = "auth_status"
|
||||
CLIENT_ID = "client_id"
|
||||
CLIENT_SECRET = "client_secret"
|
||||
USER_ID = "user_id"
|
||||
ACCESS_TOKEN = "access_token"
|
||||
REFRESH_TOKEN = "refresh_token"
|
||||
EXPIRED_TIME = "expired_time"
|
||||
FOLDER_ID = "folder_id"
|
||||
)
|
||||
|
||||
type Tencentdocument struct {
|
||||
db.ModelWithUID
|
||||
AuthUID string `gorm:"type:char(32);index"`
|
||||
UserUID string `gorm:"type:char(32)"`
|
||||
SecretID string `gorm:"type:varchar(64)"`
|
||||
SecretKey string `gorm:"type:varchar(64)"`
|
||||
AuthUID string `gorm:"type:char(32);index"`
|
||||
UserUID string `gorm:"type:char(32)"`
|
||||
UserID string `gorm:"type:varchar(64)"`
|
||||
AccessToken string `gorm:"type:varchar(512)"`
|
||||
RefreshToken string `gorm:"type:varchar(512)"`
|
||||
ExpiredTime db.Time
|
||||
}
|
||||
|
||||
func init() { db.CmdModels("", &Tencentdocument{}) }
|
||||
|
@ -1,35 +1,97 @@
|
||||
package tencentdocument
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"shylinux.com/x/ice"
|
||||
"shylinux.com/x/icebergs/base/web"
|
||||
kit "shylinux.com/x/toolkits"
|
||||
|
||||
"shylinux.com/x/community/src/api"
|
||||
"shylinux.com/x/community/src/gonganxitong"
|
||||
"shylinux.com/x/community/src/renzhengshouquan"
|
||||
"shylinux.com/x/community/src/renzhengshouquan/model"
|
||||
"shylinux.com/x/community/src/renzhengshouquan/external/tencentdocument/model"
|
||||
)
|
||||
|
||||
type tencentdocument struct {
|
||||
renzhengshouquan.Table
|
||||
order string `data:"13"`
|
||||
fields string `data:"secret_id,secret_key,user_uid"`
|
||||
create string `name:"create secret_id* secret_key*" role:"leader"`
|
||||
remove string `name:"remove" role:"leader"`
|
||||
client_id string `data:""`
|
||||
client_secret string `data:""`
|
||||
order string `data:"13"`
|
||||
fields string `data:"user_id,access_token,expired_time,user_uid"`
|
||||
auth string `name:"auth" help:"授权" role:"void"`
|
||||
remove string `name:"remove" role:"leader"`
|
||||
config string `name:"config folder_id*:select" style:"notice" role:"leader"`
|
||||
}
|
||||
|
||||
func (s tencentdocument) List(m *ice.Message, arg ...string) {
|
||||
s.ValueList(m, arg).Display("")
|
||||
kit.If(m.Length() > 0, func() { m.Action() })
|
||||
func (s tencentdocument) Inputs(m *ice.Message, arg ...string) {
|
||||
switch arg[0] {
|
||||
case model.FOLDER_ID:
|
||||
s.Folder(m, m.Option(model.AUTH_UID)).Cut(arg[0], model.NAME)
|
||||
m.DisplayInputKeyNameIconTitle()
|
||||
}
|
||||
}
|
||||
func (s tencentdocument) AuthLink(m *ice.Message, arg ...string) {
|
||||
s.Select(m, model.AUTH_UID, s.GetAuthUID(m))
|
||||
m.Echo(kit.MergeURL("https://docs.qq.com/oauth/v2/authorize",
|
||||
"client_id", m.Append("secret_id"),
|
||||
"redirect_uri", m.MergePodCmd("", m.PrefixKey()),
|
||||
"response_type", "code",
|
||||
"scope", "all",
|
||||
"state", m.Option(model.PLACE_UID),
|
||||
))
|
||||
func (s tencentdocument) List(m *ice.Message, arg ...string) {
|
||||
if len(arg) == 1 {
|
||||
s.ValueList(m, arg).Action(s.Auth).Display("")
|
||||
if m.Length() == 0 {
|
||||
s.Button(m.SetResult(), "请授权访问腾讯文档", s.Auth)
|
||||
}
|
||||
} else if len(arg) == 2 {
|
||||
m.Cmdy(api.RENZHENGSHOUQUAN_AUTH, arg[0]).Table(func(value ice.Maps) {
|
||||
if renzhengshouquan.AuthStatus(kit.Int(value[model.AUTH_STATUS])) == renzhengshouquan.AuthIssued {
|
||||
m.PushButton(s.Config)
|
||||
} else {
|
||||
m.PushButton()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
func (s tencentdocument) Config(m *ice.Message, arg ...string) {
|
||||
// m.Cmdy(api.GONGANXITONG_DOCUMENT, s.Config, m.OptionSimple(model.PLACE_UID, model.USER_UID, "folder_id"), model.VENDOR, m.PrefixKey())
|
||||
m.Cmdy("web.team.gonganxitong.document", s.Config, m.OptionSimple(model.PLACE_UID, model.USER_UID, model.FOLDER_ID), model.VENDOR, m.PrefixKey())
|
||||
}
|
||||
func (s tencentdocument) Folder(m *ice.Message, arg ...string) *ice.Message {
|
||||
msg := s.Select(m.Spawn(), model.AUTH_UID, arg[0])
|
||||
if msg.Length() == 0 {
|
||||
m.Echo("请联系公司管理员, 授权访问腾讯文档")
|
||||
return m
|
||||
}
|
||||
m.Options(web.SPIDE_HEADER, map[string]string{
|
||||
"Client-Id": m.Config(model.CLIENT_ID), "Open-Id": msg.Append(model.USER_ID), "Access-Token": msg.Append(model.ACCESS_TOKEN),
|
||||
}).Cmdy(web.SPIDE, ice.DEV, web.SPIDE_RAW, kit.MergeURL("https://docs.qq.com/openapi/drive/v2/folders/"+kit.Select("", arg, 1)))
|
||||
kit.For(kit.Value(kit.UnMarshal(m.Result()), "data.list"), func(value ice.Map) {
|
||||
value["browse_time"] = time.Unix(kit.Int64(value["lastBrowseTime"]), 0).Format(ice.MOD_TIME)
|
||||
m.PushRecord(value, "browse_time", "type", "title", "ownerName", "url", "ID")
|
||||
})
|
||||
m.RenameAppend("title", model.NAME, "url", model.LINK, "ID", model.FOLDER_ID)
|
||||
return m
|
||||
}
|
||||
func (s tencentdocument) Auth(m *ice.Message, arg ...string) {
|
||||
if m.Option("code") == "" {
|
||||
m.ProcessOpen(kit.MergeURL("https://docs.qq.com/oauth/v2/authorize",
|
||||
model.CLIENT_ID, m.Config(model.CLIENT_ID),
|
||||
"redirect_uri", m.MergePodCmd("", m.PrefixKey()+"/action/auth"),
|
||||
"response_type", "code", "scope", "all", "state", m.Option(model.AUTH_UID),
|
||||
))
|
||||
} else {
|
||||
m.Cmdy(web.SPIDE, ice.DEV, kit.MergeURL("https://docs.qq.com/oauth/v2/token",
|
||||
model.CLIENT_ID, m.Config(model.CLIENT_ID), model.CLIENT_SECRET, m.Config(model.CLIENT_SECRET),
|
||||
"redirect_uri", m.MergePodCmd("", m.PrefixKey()+"/action/auth"),
|
||||
"grant_type", "authorization_code", "code", m.Option("code"),
|
||||
))
|
||||
if m.IsErr() {
|
||||
return
|
||||
}
|
||||
m.Append(model.EXPIRED_TIME, m.Time(m.Append("expires_in")+"s"))
|
||||
s.Insert(m, kit.Simple(model.AUTH_UID, m.Option("state"), m.OptionSimple(model.USER_UID),
|
||||
m.AppendSimple(model.USER_ID, model.ACCESS_TOKEN, model.REFRESH_TOKEN, model.EXPIRED_TIME))...)
|
||||
if m.IsWeixinUA() {
|
||||
m.ProcessBack("-2")
|
||||
} else {
|
||||
m.ProcessClose()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func init() { ice.TeamCtxCmd(tencentdocument{}) }
|
||||
|
@ -1,7 +1,8 @@
|
||||
Volcanos(chat.ONIMPORT, {
|
||||
_init: function(can, msg) {
|
||||
can.onimport.myView(can, msg, function(value) { return [
|
||||
{view: html.TITLE, list: [value.secret_id]},
|
||||
{view: html.TITLE, list: [value.user_id]},
|
||||
{view: html.TITLE, list: [value.expired_time]},
|
||||
] })
|
||||
},
|
||||
})
|
@ -4,6 +4,7 @@
|
||||
"tencentdocument": "https://img.icons8.com/officel/80/documents.png"
|
||||
},
|
||||
"input": {
|
||||
"folder_id": "目录",
|
||||
"secret_id": "SecretID",
|
||||
"secret_key": "SecretKey"
|
||||
}
|
||||
|
5
src/renzhengshouquan/external/tencentdocument/tencentdocument.shy
vendored
Normal file
5
src/renzhengshouquan/external/tencentdocument/tencentdocument.shy
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
chapter "腾讯文档"
|
||||
refer `
|
||||
后台 https://docs.qq.com/open/developers/#/application/fd9733e76cef4dab9f2cc57d8ae3bd29
|
||||
文档 https://docs.qq.com/open/document/app/get_started.html
|
||||
`
|
@ -40,13 +40,15 @@ func (s tencentmeeting) Inputs(m *ice.Message, arg ...string) {
|
||||
switch arg[0] {
|
||||
case model.USER_ID:
|
||||
s.UserList(m, m.Option(model.AUTH_UID)).Cut(arg[0], "username")
|
||||
m.RenameAppend("username", "name")
|
||||
m.DisplayInputKeyNameIconTitle()
|
||||
}
|
||||
}
|
||||
func (s tencentmeeting) List(m *ice.Message, arg ...string) {
|
||||
if len(arg) == 1 {
|
||||
s.ValueList(m, arg).Display("")
|
||||
kit.If(m.Length() > 0, func() { m.Action() })
|
||||
} else {
|
||||
} else if len(arg) == 2 {
|
||||
m.Cmdy(api.RENZHENGSHOUQUAN_AUTH, arg[0]).Table(func(value ice.Maps) {
|
||||
if renzhengshouquan.AuthStatus(kit.Int(value[model.AUTH_STATUS])) == renzhengshouquan.AuthIssued {
|
||||
m.PushButton(s.Config)
|
||||
|
@ -46,6 +46,7 @@ const (
|
||||
ADDRESS = "address"
|
||||
MOBILE = "mobile"
|
||||
VERIFY = "verify"
|
||||
VENDOR = "vendor"
|
||||
)
|
||||
|
||||
type UserAuth struct {
|
||||
|
Loading…
x
Reference in New Issue
Block a user