تخطَّ إلى المستندات
Ruby

الأدوار

`roles.list` و`list_all` و`iterate` و`get` و`create` و`update` و`delete` و`list_permissions`.

كل الدوالّ

roles.rb
page = client.roles.listputs page.items.size role = client.roles.get("role_8b1f4c2e9a7d3b60e5f1a2c4")puts role[:name] support = client.roles.create(  name: "Support",  description: "Answers the shared inboxes and nothing else.",  permissions: ["emails:send", "threads:write", "labels:write"]) p support[:permissions] client.roles.update(support[:id], permissions: [*support[:permissions], "templates:read"]) client.roles.delete(support[:id], reassign_to: role[:id]) vocabulary = client.roles.list_permissionsp vocabulary.map { |permission| permission[:id] }

يحمل support[:permissions] ستة عناصر لا ثلاثة: فـ emails:send يجلب معه emails:read، وthreads:write يجلب threads:read، وlabels:write يجلب labels:read. اقرأ القائمة من الاستجابة بدل افتراضها.

يعيد list صفحة OpenEmail::Page واحدة، ويعيد list_all كل الأدوار في Array واحدة، ويمرّر iterate كل دور إلى كتلة أو يعيد Enumerator دونها. ويعود الدور في صورة Hash بمفاتيح من نوع Symbol، فيقرأ role[:permissions] القائمة. ويأخذ create وupdate حقول المتن كوسائط مسمّاة أو كـ Hash واحد، بينما يأخذ delete الوسيط reassign_to:، وهو وسيط مسمّى بصيغة snake_case يعيد الـ gem تسميته لأجل API.

الدور يقول ما يجوز لشخص أن يفعله. أما العناوين التي يجوز له أن يفعله عليها فهي المحور الآخر وتقيم في client.members: انظر grant_address وrevoke_address في صفحة الأعضاء. فجملة «يجوز له إرسال البريد» وجملة «يجوز له الإرسال باسم invoices@» جملتان مختلفتان، ومساحة عمل توظّف وكيل دعم ثانيًا تغيّر الثانية دون المساس بالأولى. وثمة صلاحية واحدة تجيب عن الجملتين معًا: الدور الذي يحمل addresses:all يصل إلى كل عنوان، بما في ذلك العناوين المضافة لاحقًا، بلا منح، ولا يستطيع وضعها على دور إلا شخص في التطبيق.

تفرّع على editable وdeletable لا على builtin ولا على الاسم. فكلاهما false للمالك وحده، الذي قائمته هي «كل صلاحية، بما فيها ما سيُخترع العام المقبل» وتُحسب ولا تُخزَّن. وكل دور آخر يجيب true عليهما، بما في ذلك الأدوار الخمسة التي تبدأ بها مساحة العمل. والدور الذي أعاد أحدهم تسميته يظل يجيب عنهما بصدق، ولم يعد اسمه يخبرك بشيء.

يستبدل update قائمة الصلاحيات كاملةً. ولا يوجد استدعاء لمنح صلاحية واحدة، فاقرأ الدور، وغيّر العنصر الذي تقصده، وأعد إرسالها جميعًا، كما يفعل [*support[:permissions], "templates:read"] أعلاه. وإرسال صلاحية واحدة يترك الدور حاملًا تلك الصلاحية وحدها، مع ما تستلزمه.

يحتاج delete إلى reassign_to: فور أن يحمل أحدٌ الدور. ويرسله الـ gem بوصفه معامل الاستعلام reassignTo، لأن متن طلب DELETE تُسقطه عدة بيئات تشغيل وعدد من الوسطاء، ويترك المعامل حين لا تمرّر شيئًا. وتبلّغ النتيجة عن reassigned وkeysReassigned كلٍّ على حدة، فيتمكن السكربت من تسجيل ما فعله لا ما طلبه.

إن list_permissions هو GET /roles/permissions، مسار ثابت يقع تمامًا حيث يقع معرّف الدور. ويستدعي الـ gem ذلك المسار مباشرة بدل تمرير الكلمة عبر get، ويعيد Array بسيطة، لا OpenEmail::Page: Hash واحد لكل صلاحية، فيه id وlabel وgroup وscope. وتعلّم scope: false العناصر التي لا يمكن لأي مفتاح أن يحملها أبدًا. لا تمرّر الكلمة إلى get بنفسك. فـ client.roles.get("permissions") يبني المسار نفسه، فيرسل الطلب نفسه ويعيد المفردات لا دورًا ولا 404.

الدور هو سقف المفتاح

المفتاح الصادر مقابل دور يجوز له ما يقع في تقاطع نطاقاته الخاصة مع صلاحيات ذلك الدور، ويُحسم ذلك لكل طلب عند الحدود. فتضييق دور يسحب صلاحيات مفاتيحه فورًا دون تدوير أي منها. والمفتاح بلا دور ليس له سقف إطلاقًا، وهو ما يجعل roleId بقيمة nil أوسع حالة يمكن للمفتاح أن يكون فيها لا أضيقها.

ولهذا أيضًا يصرّ roles.delete على وجهة تُنقل إليها المفاتيح. فتيتيمها كان سيسقط سقفها بالكامل، ويرفع صامتًا كل اعتماد كان الدور يحدّه.

يبلّغ GET /keys/self وGET /ping عن roleId وgrantedScopes إلى جانب scopes الفعلية. وهكذا يُجاب عن «مفتاحي يحمل emails:send ومع ذلك أتلقى insufficient_scope»: فكل ما هو في grantedScopes وغائب عن scopes قد أخذه الدور. ويعيد client.me.get وclient.me.ping كليهما في الـ Hash الخاص بهما، فيسرد key[:grantedScopes] - key[:scopes] ما أخذه الدور. والرفض نفسه OpenEmail::PermissionError تكون قيمة scope_missing? فيه true.

المعاملات

nameStringمطلوب
ما تسمّي به مساحة العمل الدور: من 1 إلى 48 حرفًا، ويُشذَّب الفراغ قبل التخزين. والأسماء فريدة في كل مساحة عمل دون اعتبار لحالة الأحرف، فيُرفض دور ثانٍ باسم «Support» بـ `role_name_taken` (409)، المرفوع في صورة `OpenEmail::ConflictError`، بدل إنشائه إلى جانب الأول.
descriptionString
جملة تقول ما الدور لأجله، يُشذَّب فراغها وطولها 240 حرفًا كحد أقصى. والسلسلة التي تصير فارغة بعد التشذيب تُخزَّن كـ nil، فوصف مكوَّن من فراغات يعود nil لا كما أرسلته. وفي `create`، اتركه بدل تمرير nil: فالـ gem يرسل nil كما هو، ويرفضه `create` بـ 422. وفي `update`، يمسحه `description: nil`.
permissionsArray<String>مطلوب
ما يمنحه الدور، مأخوذًا من المفردات التي يقدّمها `list_permissions`. والسلسلة التي ليست منها تعطي 422 على `permissions`، يُرفع في صورة `OpenEmail::ValidationError` مع ضبط `param` على `permissions`، بدل إسقاطها صامتةً، فيُبلَّغ عن الخطأ المطبعي بدل أن يكلّفك بعد ظهيرة كاملة. وتُوسَّع القائمة عند الدخول (فـ `templates:write` يخزّن `templates:read` إلى جانبه)، ويُزال تكرارها وتُعاد إلى الترتيب المعياري، فاقرأ القائمة المخزَّنة من الاستجابة بدل افتراض أنها التي أرسلتها.

الاستجابة

objectString
دائمًا `role`. وتجيب علامة الحذف بالقيمة نفسها، و`id` الخاص بالدور، و`deleted: true`، وعددَي إعادة الإسناد، ولا شيء من الحقول الأخرى أدناه.
idString
معرّف الدور، يُقرأ بوصفه `role[:id]`. وهو ما يسمّيه `roleId` الخاص بالعضو، وما يشير إليه سقف مفتاح API، وما يأخذه `reassign_to:` حين يُحذف دور آخر وينتقل حاملوه إلى هذا الدور.
nameString
اسم الدور في مساحة العمل، مشذَّب وفريد دون اعتبار لحالة الأحرف. ويمكن إعادة تسمية كل دور عدا دور المالك، بما فيها الأدوار الأولية (فـ `builtin` يقول من أين جاء الصف، لا ما يجب أن يبقى اسمه)، فلا تقرأ «Admin» على أنه وعد بما يحمله الدور. والاسم الذي يحمله دور آخر بالفعل يعطي `role_name_taken` (409، مع ضبط `param` على `name`). وإعادة تسمية دور المالك تعطي `role_immutable` (409)، مثل أي تعديل آخر عليه.
descriptionString or nil
الجملة التي تصف الدور، أو nil حين لا تُعطى. والمدخل الفارغ يُخزَّن كـ nil في الإنشاء والتحديث كليهما، فلا تكون هذه سلسلة فارغة أبدًا.
permissionsArray<String>
كل ما يمنحه الدور، موسَّعًا مسبقًا وبالترتيب المعياري لا بالترتيب الذي كتبه أحد. وذلك الترتيب أساسي: فدوران يحملان الصلاحيات نفسها يحملان مصفوفتي Array متساويتين، وهو ما يتيح لشاشة الإعدادات أن تقارنهما بـ `==` لتقرر ما إذا كان زر الحفظ مفعّلًا.
builtinString or nil
أي الأدوار الأولية الستة جاء منه هذا الصف، `owner` أو `admin` أو `member` أو `viewer` أو `developer` أو `billing`، أو nil لدور كتبته مساحة العمل بنفسها. وهو يسجّل الأصل لا الحالة: فالدور الأولي يُعاد تسميته وتُغيَّر صلاحياته ويُحذف كأي دور آخر. تفرّع على `editable` و`deletable` لا على هذا الحقل. فالدور الذي سمّاه أحدهم «Admin» ليس بالضرورة الدور الأولي، والدور الأولي قد لا يعود اسمه كذلك.
editableBoolean
يُحسب بوصفه `builtin != "owner"`، فيكون false لدور المالك وحده، ويُرفض كل `update` لذلك الدور بـ `role_immutable` (409). وكل دور آخر قابل للتعديل بالكامل (الاسم والوصف والصلاحيات)، بما في ذلك الأدوار الخمسة التي تبدأ بها مساحة العمل.
deletableBoolean
يُحسب بوصفه `builtin != "owner"`: false لدور المالك وحده، الذي يعود بـ `role_undeletable` (409)، وtrue لكل دور آخر بما فيها الأدوار الأولية. افحصه قبل عرض الزر لا بعد الرفض. والدور الذي ما زال أحد يحمله يحتاج أيضًا إلى `reassign_to:`، وإلا أعطى الحذف `role_in_use` (409). ويُرفع الرفضان في صورة `OpenEmail::ConflictError`، ويميّز `code` بينهما.
membersInteger
كم شخصًا يحمل هذا الدور، محسوبًا من صفوف أعضاء مساحة العمل. والمالك ليس بينهم: فليس له صف عضوية ولا يمكن منحه دورًا، فيبلّغ دور Owner بصفر حاملين رغم أن قائمة الأعضاء تعرضه.
apiKeysInteger
كم مفتاح API حي يحدّه هذا الدور. وتُستثنى المفاتيح الملغاة من العدّ، رغم أن الحذف يعيد توجيه كل صف مفتاح يشير إلى الدور، بما فيها الملغاة. وهي الفئة الثانية التي يجب نقلها قبل أن يذهب الدور، والفئة التي لا ينتبه إليها أحد: فالمفاتيح برامج، والبرنامج لا يشتكي.
createdAtString
متى كُتب صف الدور، في صورة String بصيغة ISO 8601. وتُنشأ الصفوف المدمجة بتكاسل في أول مرة يحتاج إليها شيء، مثل قراءة قائمة الأدوار أو إنشاء دور أو شاشة مفاتيح API، لا عند إنشاء مساحة العمل. فالطابع الزمني للدور المدمج هو وقت وصول ذلك الطلب الأول لا وقت إنشاء مساحة العمل.
updatedAtString
متى تغيّر الدور آخر مرة، في صورة String بصيغة ISO 8601. وكل `update` مقبول يحرّكه، بما في ذلك تحديث يضبط حقلًا على القيمة التي كان يحملها أصلًا.