keyFrom((string) $project->getTranslation('slug', $locale, false)); if ($key === null) { throw ValidationException::withMessages(['taskstream_key' => __('rules.taskstream.key_needed')]); } try { $created = $this->client->createProject( token: $this->token($user, $bearer), key: $key, name: Str::limit((string) $project->getTranslation('title', $locale, false), 80, '…'), description: $project->getTranslation('tagline', $locale, false) ?: null, public: true, ); } catch (TaskStreamException $e) { throw $this->explain($e); } $project->forceFill([ 'taskstream_project_id' => $created['id'], 'taskstream_key' => $created['key'], ]); } /** * A Pireon token is passed on, so the board belongs to whoever asked. A * machine token is this application's alone and means nothing there. */ protected function token(User $user, ?string $bearer): string { $token = $user->currentAccessToken() === null ? $bearer : $this->client->serviceToken(); if (blank($token)) { throw ValidationException::withMessages(['taskstream' => __('rules.taskstream.machine')]); } return $token; } /** * A key in TaskStream's style: one word gives its first ten characters * ("catalogo" → CATALOGO), several give their initials ("mi-web-nueva" * → MWN). Null when nothing usable is left. */ public function keyFrom(string $slug): ?string { $words = array_values(array_filter(preg_split('/[^A-Z0-9]+/', Str::upper(Str::ascii($slug))) ?: [])); $key = count($words) === 1 ? $words[0] : implode('', array_map(fn (string $word) => $word[0], $words)); // It must start with a letter. $key = substr((string) preg_replace('/^[0-9]+/', '', $key), 0, 10); return preg_match(self::KEY_PATTERN, $key) === 1 ? $key : null; } protected function explain(TaskStreamException $e): ValidationException|HttpException { if ($e->isRefusal()) { return ValidationException::withMessages([ 'taskstream_key' => __('rules.taskstream.refused', ['reason' => $e->getMessage()]), ]); } if ($e->isUnauthorised()) { return ValidationException::withMessages(['taskstream' => __('rules.taskstream.unauthorised')]); } return new HttpException(502, __('rules.taskstream.unavailable'), $e); } }