diff --git a/app/Device.php b/app/Device.php
index 931f6572df..eb367175fc 100644
--- a/app/Device.php
+++ b/app/Device.php
@@ -15,15 +15,38 @@ class Device extends Model implements Auditable
use HasFactory;
const REPAIR_STATUS_FIXED = 1;
+ const REPAIR_STATUS_FIXED_STR = 'Fixed';
const REPAIR_STATUS_REPAIRABLE = 2;
+ const REPAIR_STATUS_REPAIRABLE_STR = 'Repairable';
const REPAIR_STATUS_ENDOFLIFE = 3;
+ const REPAIR_STATUS_ENDOFLIFE_STR = 'End of life';
const SPARE_PARTS_NEEDED = 1;
const SPARE_PARTS_NOT_NEEDED = 2;
const SPARE_PARTS_UNKNOWN = 0;
const PARTS_PROVIDER_MANUFACTURER = 1;
+ const PARTS_PROVIDER_MANUFACTURER_STR = 'Manufacturer';
const PARTS_PROVIDER_THIRD_PARTY = 2;
+ const PARTS_PROVIDER_THIRD_PARTY_STR = 'Third party';
+ const PARTS_PROVIDER_NO = 0;
+ const PARTS_PROVIDER_NO_STR = 'No';
+
+ const BARRIER_SPARE_PARTS_NOT_AVAILABLE = 1;
+ const BARRIER_SPARE_PARTS_NOT_AVAILABLE_STR = 'Spare parts not available';
+ const BARRIER_SPARE_PARTS_TOO_EXPENSIVE = 2;
+ const BARRIER_SPARE_PARTS_TOO_EXPENSIVE_STR = 'Spare parts too expensive';
+ const BARRIER_NO_WAY_TO_OPEN_THE_PRODUCT = 3;
+ const BARRIER_NO_WAY_TO_OPEN_THE_PRODUCT_STR = 'No way to open the product';
+ const BARRIER_REPAIR_INFORMATION_NOT_AVAILABLE = 4;
+ const BARRIER_REPAIR_INFORMATION_NOT_AVAILABLE_STR = 'Repair information not available';
+ const BARRIER_LACK_OF_EQUIPMENT = 5;
+ const BARRIER_LACK_OF_EQUIPMENT_STR = 'Lack of equipment';
+
+ const NEXT_STEPS_MORE_TIME_NEEDED_STR = 'More time needed';
+ const NEXT_STEPS_PROFESSIONAL_HELP_STR = 'Professional help';
+ const NEXT_STEPS_DO_IT_YOURSELF_STR = 'Do it yourself';
+
use \OwenIt\Auditing\Auditable;
protected $table = 'devices';
@@ -33,7 +56,7 @@ class Device extends Model implements Auditable
*
* @var array
*/
- protected $fillable = ['event', 'category', 'category_creation', 'estimate', 'repair_status', 'spare_parts', 'parts_provider', 'brand', 'item_type', 'model', 'age', 'problem', 'notes', 'repaired_by', 'do_it_yourself', 'professional_help', 'more_time_needed', 'wiki', 'fault_type'];
+ protected $fillable = ['event', 'category', 'category_creation', 'estimate', 'repair_status', 'spare_parts', 'parts_provider', 'brand', 'item_type', 'model', 'age', 'problem', 'notes', 'repaired_by', 'do_it_yourself', 'professional_help', 'more_time_needed', 'wiki', 'fault_type', 'reference'];
/**
* The attributes that should be hidden for arrays.
diff --git a/app/DeviceBarrier.php b/app/DeviceBarrier.php
index 5b27f40518..4eaa637700 100644
--- a/app/DeviceBarrier.php
+++ b/app/DeviceBarrier.php
@@ -7,7 +7,7 @@
class DeviceBarrier extends Model
{
protected $table = 'devices_barriers';
- protected $fillable = ['device_id', 'barrier'];
+ protected $fillable = ['device_id', 'barrier_id'];
protected $hidden = [];
public $timestamps = false;
}
diff --git a/app/Http/Controllers/API/DeviceController.php b/app/Http/Controllers/API/DeviceController.php
new file mode 100644
index 0000000000..c2d6ce1a74
--- /dev/null
+++ b/app/Http/Controllers/API/DeviceController.php
@@ -0,0 +1,629 @@
+getUser();
+
+ list($eventid,
+ $category,
+ $item_type,
+ $brand,
+ $model,
+ $age,
+ $estimate,
+ $problem,
+ $notes,
+ $repair_status,
+ $spare_parts,
+ $parts_provider,
+ $professional_help,
+ $more_time_needed,
+ $do_it_yourself,
+ $barrier,
+ $reference
+ ) = $this->validateDeviceParams($request,true);
+
+ // We may have uploaded photos before creation, and we have a draft id which allows us to patch that
+ // up.
+ $draftId = $request->input('id');
+
+ $event = Party::findOrFail($eventid);
+
+ if (!Fixometer::userHasEditEventsDevicesPermission($eventid, $user->id)) {
+ // Only hosts can add devices to events.
+ abort(403);
+ }
+
+ $data = [
+ 'event' => $eventid,
+ 'category' => $category,
+ 'category_creation' => $category, // We don't expose this over the API but we record it in case it changes.
+ 'item_type' => $item_type,
+ 'brand' => $brand,
+ 'model' => $model,
+ 'age' => $age,
+ 'estimate' => $estimate,
+ 'problem' => $problem,
+ 'notes' => $notes,
+ 'repair_status' => $repair_status,
+ 'spare_parts' => $spare_parts,
+ 'parts_provider' => $parts_provider,
+ 'professional_help' => $professional_help,
+ 'more_time_needed' => $more_time_needed,
+ 'do_it_yourself' => $do_it_yourself,
+ 'repaired_by' => $user->id,
+ 'reference' => $reference
+ ];
+
+ $device = Device::create($data);
+ $idDevice = $device->iddevices;
+
+ if ($idDevice) {
+ event(new DeviceCreatedOrUpdated($device));
+
+ if ($barrier) {
+ DeviceBarrier::create([
+ 'device_id' => $idDevice,
+ 'barrier_id' => $barrier
+ ]);
+ }
+
+ // We might have some photos uploaded for this device. Record them against this device instance.
+ // Each instance of a device shares the same underlying photo file.
+ $File = new \FixometerFile;
+ $images = $File->findImages(env('TBL_DEVICES'), $draftId);
+ foreach ($images as $image) {
+ $xref = Xref::findOrFail($image->idxref);
+ $xref->copy($idDevice);
+ }
+
+ // If the number of devices exceeds set amount then notify admins.
+ $deviceMiscCount = DB::table('devices')->where('category', env('MISC_CATEGORY_ID_POWERED'))->where('event', $eventid)->count() +
+ DB::table('devices')->where('category', env('MISC_CATEGORY_ID_UNPOWERED'))->where('event', $eventid)->count();
+ if ($deviceMiscCount == env('DEVICE_ABNORMAL_MISC_COUNT', 5)) {
+ $notify_users = Fixometer::usersWhoHavePreference('admin-abnormal-devices');
+ Notification::send($notify_users, new AdminAbnormalDevices([
+ 'event_venue' => $event->getEventName(),
+ 'event_url' => url('/party/edit/'.$eventid),
+ ]));
+ }
+ }
+
+ // We return the device and the stats to save the client another API call to update its store.
+
+ return response()->json([
+ 'id' => $idDevice,
+ 'device' => \App\Http\Resources\Device::make($device),
+ 'stats' => $event->getEventStats()
+ ]);
+ }
+
+ /**
+ * @OA\Patch(
+ * path="/api/v2/devices/{id}",
+ * operationId="editDevice",
+ * tags={"Devices"},
+ * summary="Edit Device",
+ * description="Edits a device.",
+ * @OA\Parameter(
+ * name="api_token",
+ * description="A valid user API token",
+ * required=true,
+ * in="query",
+ * @OA\Schema(
+ * type="string",
+ * example="1234"
+ * )
+ * ),
+ * @OA\RequestBody(
+ * @OA\MediaType(
+ * mediaType="multipart/form-data",
+ * @OA\Schema(
+ * required={"category","item_type"},
+ * @OA\Property(
+ * property="eventid",
+ * title="id",
+ * description="Unique identifier of the event to which the device belongs",
+ * format="int64",
+ * example=1
+ * ),
+ * @OA\Property(
+ * property="category",
+ * ref="#/components/schemas/Device/properties/category",
+ * ),
+ * @OA\Property(
+ * property="item_type",
+ * ref="#/components/schemas/Device/properties/item_type",
+ * ),
+ * @OA\Property(
+ * property="brand",
+ * ref="#/components/schemas/Device/properties/brand",
+ * ),
+ * @OA\Property(
+ * property="model",
+ * ref="#/components/schemas/Device/properties/model",
+ * ),
+ * @OA\Property(
+ * property="age",
+ * ref="#/components/schemas/Device/properties/age",
+ * ),
+ * @OA\Property(
+ * property="estimate",
+ * ref="#/components/schemas/Device/properties/estimate",
+ * ),
+ * @OA\Property(
+ * property="problem",
+ * ref="#/components/schemas/Device/properties/problem",
+ * ),
+ * @OA\Property(
+ * property="notes",
+ * ref="#/components/schemas/Device/properties/notes",
+ * ),
+ * @OA\Property(
+ * property="repair_status",
+ * ref="#/components/schemas/Device/properties/repair_status",
+ * ),
+ * @OA\Property(
+ * property="next_steps",
+ * ref="#/components/schemas/Device/properties/next_steps",
+ * ),
+ * @OA\Property(
+ * property="spare_parts",
+ * ref="#/components/schemas/Device/properties/spare_parts",
+ * ),
+ * @OA\Property(
+ * property="barrier",
+ * ref="#/components/schemas/Device/properties/barrier",
+ * ),
+ * @OA\Property(
+ * property="reference",
+ * ref="#/components/schemas/Device/properties/reference",
+ * ),
+ * )
+ * )
+ * ),
+ * @OA\Response(
+ * response=200,
+ * description="Successful operation",
+ * @OA\JsonContent(
+ * @OA\Property(
+ * property="data",
+ * title="data",
+ * ref="#/components/schemas/Device"
+ * )
+ * ),
+ * )
+ * )
+ */
+ public function updateDevicev2(Request $request, $iddevices)
+ {
+ $user = $this->getUser();
+
+ list($eventid,
+ $category,
+ $item_type,
+ $brand,
+ $model,
+ $age,
+ $estimate,
+ $problem,
+ $notes,
+ $repair_status,
+ $spare_parts,
+ $parts_provider,
+ $professional_help,
+ $more_time_needed,
+ $do_it_yourself,
+ $barrier,
+ $reference
+ ) = $this->validateDeviceParams($request,false);
+
+ $event = Party::findOrFail($eventid);
+
+ if (!Fixometer::userHasEditEventsDevicesPermission($eventid, $user->id)) {
+ // Only hosts can add devices to events.
+ abort(403);
+ }
+
+ $data = [
+ 'event' => $eventid,
+ 'category' => $category,
+ 'item_type' => $item_type,
+ 'brand' => $brand,
+ 'model' => $model,
+ 'age' => $age,
+ 'estimate' => $estimate,
+ 'problem' => $problem,
+ 'notes' => $notes,
+ 'repair_status' => $repair_status,
+ 'spare_parts' => $spare_parts,
+ 'parts_provider' => $parts_provider,
+ 'professional_help' => $professional_help,
+ 'more_time_needed' => $more_time_needed,
+ 'do_it_yourself' => $do_it_yourself,
+ 'repaired_by' => $user->id,
+ 'reference' => $reference
+ ];
+
+ $device = Device::findOrFail($iddevices);
+ $device->update($data);
+
+ event(new DeviceCreatedOrUpdated($device));
+
+ if ($barrier) {
+ // We only allow one barrier now, so delete any old ones.
+ DeviceBarrier::where('device_id', $iddevices)->delete();
+ DeviceBarrier::create([
+ 'device_id' => $iddevices,
+ 'barrier_id' => $barrier
+ ]);
+ }
+
+ return response()->json([
+ 'id' => $iddevices,
+ 'device' => \App\Http\Resources\Device::make($device),
+ 'stats' => $event->getEventStats()
+ ]);
+ }
+
+ /**
+ * @OA\Delete(
+ * path="/api/v2/devices/{id}",
+ * operationId="deleteDevice",
+ * tags={"Devices"},
+ * summary="Delete Device",
+ * description="Deletes a device.",
+ * @OA\Parameter(
+ * name="id",
+ * description="Device id",
+ * required=true,
+ * in="path",
+ * @OA\Schema(
+ * type="integer"
+ * )
+ * ),
+ * @OA\Response(
+ * response=200,
+ * description="Successful operation",
+ * ),
+ * @OA\Response(
+ * response=404,
+ * description="Device not found",
+ * ),
+ * )
+ */
+
+ public function deleteDevicev2(Request $request, $iddevices)
+ {
+ $user = $this->getUser();
+
+ $device = Device::findOrFail($iddevices);
+ $eventid = $device->event;
+
+ if (!Fixometer::userHasEditEventsDevicesPermission($device->event, $user->id)) {
+ // Only hosts can delete devices for events.
+ abort(403);
+ }
+
+ $device->delete();
+
+ $event = Party::findOrFail($eventid);
+
+ return response()->json([
+ 'id' => $iddevices,
+ 'stats' => $event->getEventStats()
+ ]);
+ }
+
+ private function validateDeviceParams(Request $request, $create): array
+ {
+ // We don't validate max lengths of other strings, to avoid duplicating the length information both here
+ // and in the migrations. If we wanted to do that we should extract the length dynamically from the
+ // schema, which is possible but not trivial.
+ $request->validate([
+ 'eventid' => 'required|integer',
+ 'item_type' => 'string', // Some of the tests, at least, treat this as optional.
+ 'category' => 'required|integer',
+ 'brand' => 'string',
+ 'model' => 'string',
+ 'age' => [ 'numeric', 'max:500' ],
+ 'estimate' => [ 'numeric', 'min:0' ],
+ 'problem' => [ 'string', 'nullable' ],
+ 'notes' => 'string',
+ 'repair_status' => [ 'string', 'in:Fixed,Repairable,End of life' ],
+ 'next_steps' => [ 'string', 'in:More time needed,Professional help,Do it yourself', 'nullable' ],
+ 'spare_parts' => [ 'string', 'in:No,Manufacturer,Third party' ],
+ 'barrier' => [ 'string', 'nullable', 'in:Spare parts not available,Spare parts too expensive,No way to open the product,Repair information not available,Lack of equipment' ],
+ 'reference' => [ 'string', 'nullable', 'max:255' ]
+ ]);
+
+ $eventid = $request->input('eventid');
+ $category = $request->input('category');
+ $item_type = $request->input('item_type');
+ $brand = $request->input('brand');
+ $model = $request->input('model');
+ $age = $request->input('age');
+ $age = $age ? $age : 0;
+ $estimate = $request->input('estimate');
+ $estimate = $estimate ? $estimate : 0;
+ $problem = $request->input('problem');
+ $notes = $request->input('notes');
+ $repair_status = $request->input('repair_status');
+ $barrierInput = $request->input('barrier');
+ $reference = $request->input('reference');
+
+ // Our database has a slightly complex structure for historical reasons, so we need to map some input
+ // values to the underlying fields. This keeps the API clean.
+ //
+ // There is mirror code in Resources\Device.
+ $problem = $problem ? $problem : '';
+ $spare_parts = Device::SPARE_PARTS_UNKNOWN;
+ $parts_provider = NULL;
+ $professional_help = 0;
+ $more_time_needed = 0;
+ $do_it_yourself = 0;
+ $barrier = 0;
+
+ switch ($repair_status) {
+ case Device::REPAIR_STATUS_FIXED_STR:
+ $repair_status = Device::REPAIR_STATUS_FIXED;
+ break;
+ case Device::REPAIR_STATUS_REPAIRABLE_STR:
+ $repair_status = Device::REPAIR_STATUS_REPAIRABLE;
+ break;
+ case Device::REPAIR_STATUS_ENDOFLIFE_STR:
+ $repair_status = Device::REPAIR_STATUS_ENDOFLIFE;
+ break;
+ default:
+ $repair_status = 0;
+ break;
+ }
+
+ if ($barrierInput) {
+ // Look up the barrier.
+ $barrierEnt = Barrier::firstOrFail()->where('barrier', $barrierInput)->get();
+ $barrier = $barrierEnt->toArray()[0]['id'];
+
+ if (!$barrier) {
+ throw ValidationException::withMessages(['barrier' => ['Invalid barrier supplied']]);
+ }
+ }
+
+ // We can provide next_steps and spare_parts for any status - this is for recording historical information.
+ if ($request->has('next_steps')) {
+ switch ($request->input('next_steps')) {
+ case Device::NEXT_STEPS_MORE_TIME_NEEDED_STR:
+ $more_time_needed = 1;
+ break;
+ case Device::NEXT_STEPS_PROFESSIONAL_HELP_STR:
+ $professional_help = 1;
+ break;
+ case Device::NEXT_STEPS_DO_IT_YOURSELF_STR:
+ $do_it_yourself = 1;
+ break;
+ }
+ }
+
+ if ($request->has('spare_parts')) {
+ switch ($request->input('spare_parts')) {
+ case Device::PARTS_PROVIDER_NO_STR:
+ $spare_parts = Device::SPARE_PARTS_NOT_NEEDED;
+ break;
+ case Device::PARTS_PROVIDER_MANUFACTURER_STR:
+ $spare_parts = Device::SPARE_PARTS_NEEDED;
+
+ if ($repair_status != Device::REPAIR_STATUS_ENDOFLIFE) {
+ // If it is end of life we record that the parts are needed, but there is no provider.
+ $parts_provider = Device::PARTS_PROVIDER_MANUFACTURER;
+ }
+ break;
+ case Device::PARTS_PROVIDER_THIRD_PARTY_STR:
+ $spare_parts = Device::SPARE_PARTS_NEEDED;
+
+ if ($repair_status != Device::REPAIR_STATUS_ENDOFLIFE) {
+ // If it is end of life we record that the parts are needed, but there is no provider.
+ $parts_provider = Device::PARTS_PROVIDER_THIRD_PARTY;
+ }
+ break;
+ }
+ }
+
+ return [
+ $eventid,
+ $category,
+ $item_type,
+ $brand,
+ $model,
+ $age,
+ $estimate,
+ $problem,
+ $notes,
+ $repair_status,
+ $spare_parts,
+ $parts_provider,
+ $professional_help,
+ $more_time_needed,
+ $do_it_yourself,
+ $barrier,
+ $reference
+ ];
+ }
+
+ private function getUser()
+ {
+ // We want to allow this call to work if a) we are logged in as a user, or b) we have a valid API token.
+ //
+ // This is a slightly odd thing to do, but it is necessary to get both the PHPUnit tests and the
+ // real client use of the API to work.
+ $user = Auth::user();
+
+ if (!$user) {
+ $user = auth('api')->user();
+ }
+
+ if (!$user) {
+ throw new AuthenticationException();
+ }
+
+ return $user;
+ }
+}
\ No newline at end of file
diff --git a/app/Http/Controllers/API/ItemController.php b/app/Http/Controllers/API/ItemController.php
index a20aca4c7f..db477afe3c 100644
--- a/app/Http/Controllers/API/ItemController.php
+++ b/app/Http/Controllers/API/ItemController.php
@@ -20,7 +20,7 @@ class ItemController extends Controller
* path="/api/v2/items",
* operationId="listItemsv2",
* tags={"Items"},
- * summary="Get list of items",
+ * summary="Get suggested list of items which could be used in a Device.",
* @OA\Response(
* response=200,
* description="Successful operation",
diff --git a/app/Http/Controllers/ApiController.php b/app/Http/Controllers/ApiController.php
index cbfe6bcb08..277105e504 100644
--- a/app/Http/Controllers/ApiController.php
+++ b/app/Http/Controllers/ApiController.php
@@ -263,15 +263,15 @@ public static function getDevices(Request $request, $page, $size)
->take($size)
->get();
- foreach ($items as &$item) {
- $item['shortProblem'] = $item->getShortProblem();
- $item['images'] = $item->getImages();
- $item['category'] = $item['deviceCategory'];
+ $item_data = [];
+
+ foreach ($items as $item) {
+ $item_data[] = (new \App\Http\Resources\Device($item))->resolve();
}
return response()->json([
'count' => $count,
- 'items' => $items,
+ 'items' => $item_data,
]);
}
diff --git a/app/Http/Controllers/DeviceController.php b/app/Http/Controllers/DeviceController.php
index f231ff8b2a..ae8942b466 100644
--- a/app/Http/Controllers/DeviceController.php
+++ b/app/Http/Controllers/DeviceController.php
@@ -66,330 +66,6 @@ public function index($search = null)
]);
}
- public function ajaxCreate(Request $request)
- {
- $rules = [
- 'category' => 'required|filled'
- ];
-
- $validator = Validator::make($request->all(), $rules);
-
- if ($validator->fails()) {
- return response()->json($validator->messages(), 200);
- }
-
- $request->validate([
- 'age' => 'nullable|numeric|max:500'
- ]);
-
- $category = $request->input('category');
- $weight = $request->filled('estimate') ? $request->input('estimate', 0) : 0;
- $brand = $request->input('brand');
- $model = $request->input('model');
- $item_type = $request->input('item_type');
- $age = $request->filled('age') ? $request->input('age',0) : 0;
- $problem = $request->input('problem');
- $notes = $request->input('notes');
- $repair_status = $request->input('repair_status');
- $repair_details = $request->input('repair_details');
- $spare_parts = $request->input('spare_parts');
- $quantity = $request->input('quantity');
- $event_id = $request->input('event_id');
- $barrier = $request->input('barrier');
-
- $iddevices = $request->input('iddevices');
-
- // Get party for later
- $event = Party::find($event_id);
-
- // add quantity loop
- for ($i = 0; $i < $quantity; $i++) {
- $device[$i] = new Device;
- $device[$i]->category = $category;
- $device[$i]->category_creation = $category;
- $device[$i]->estimate = $weight;
- $device[$i]->brand = $brand;
- $device[$i]->item_type = $item_type;
- $device[$i]->model = $model;
- $device[$i]->age = $age;
- $device[$i]->problem = $problem;
- $device[$i]->notes = $notes;
- $device[$i]->repair_status = isset($repair_status) ? $repair_status : 0;
-
- if ($repair_details == 1) {
- $device[$i]->more_time_needed = 1;
- } else {
- $device[$i]->more_time_needed = 0;
- }
-
- if ($repair_details == 2) {
- $device[$i]->professional_help = 1;
- } else {
- $device[$i]->professional_help = 0;
- }
-
- if ($repair_details == 3) {
- $device[$i]->do_it_yourself = 1;
- } else {
- $device[$i]->do_it_yourself = 0;
- }
-
- // $spare_parts as input comes from a single dropdown with three options.
- // This is mapped to corresponding DB values
- // for spare_parts and parts_provider columns.
- if ($spare_parts == 3) { // Input option was 'Third party'
- $spare_parts = Device::SPARE_PARTS_NEEDED;
- $parts_provider = Device::PARTS_PROVIDER_THIRD_PARTY;
- } elseif ($spare_parts == 1) { // Input option was 'Manufacturer'
- $spare_parts = Device::SPARE_PARTS_NEEDED;
- $parts_provider = Device::PARTS_PROVIDER_MANUFACTURER;
- } elseif ($spare_parts == 2) { // Input option was 'Not needed'
- $spare_parts = Device::SPARE_PARTS_NOT_NEEDED;
- $parts_provider = null;
- } else {
- $parts_provider = null;
- }
-
- if (! isset($barrier)) {
- $barrier = null;
- } elseif (in_array(1, $barrier) || in_array(2, $barrier)) { // 'Spare parts not available' or 'spare parts too expensive' selected
- $spare_parts = Device::SPARE_PARTS_NEEDED;
- } elseif (count($barrier) > 0) {
- $spare_parts = Device::SPARE_PARTS_NOT_NEEDED;
- }
-
- $device[$i]->spare_parts = isset($spare_parts) ? $spare_parts : Device::SPARE_PARTS_UNKNOWN;
- $device[$i]->parts_provider = $parts_provider;
- $device[$i]->event = $event_id;
- $device[$i]->repaired_by = Auth::id();
-
- $device[$i]->save();
- $device[$i]->refresh();
-
- event(new DeviceCreatedOrUpdated($device[$i]));
-
- // Update barriers
- if (isset($barrier) && ! empty($barrier) && $repair_status == Device::REPAIR_STATUS_ENDOFLIFE) {
- Device::find($device[$i]->iddevices)->barriers()->sync($barrier);
- } else {
- Device::find($device[$i]->iddevices)->barriers()->sync([]);
- }
-
- // If the number of devices exceeds set amount then show the following message
- $deviceMiscCount = DB::table('devices')->where('category', env('MISC_CATEGORY_ID_POWERED'))->where('event', $event_id)->count() +
- DB::table('devices')->where('category', env('MISC_CATEGORY_ID_UNPOWERED'))->where('event', $event_id)->count();
- if ($deviceMiscCount == env('DEVICE_ABNORMAL_MISC_COUNT', 5)) {
- $notify_users = Fixometer::usersWhoHavePreference('admin-abnormal-devices');
- Notification::send($notify_users, new AdminAbnormalDevices([
- 'event_venue' => $event->getEventName(),
- 'event_url' => url('/party/edit/'.$event_id),
- ]));
- }
-
- // Expand a few things so that the new devices are returned with the same information that existing
- // ones are returned in the view blade.
- $device[$i]->idevents = $device[$i]->event;
- $device[$i]->category = $device[$i]->deviceCategory;
- $device[$i]->shortProblem = $device[$i]->getShortProblem();
-
- $barriers = [];
-
- foreach ($device[$i]->barriers as $b) {
- $barriers[] = $b->id;
- }
-
- $device[$i]->barrier = $barriers;
-
- if ($iddevices && $iddevices < 0) {
- // We might have some photos uploaded for this device. Record them against this device instance.
- // Each instance of a device shares the same underlying photo file.
- $File = new \FixometerFile;
- $images = $File->findImages(env('TBL_DEVICES'), $iddevices);
- foreach ($images as $image) {
- $xref = Xref::findOrFail($image->idxref);
- $xref->copy($device[$i]->iddevices);
- }
-
- $device[$i]->images = $device[$i]->getImages();
- }
- }
- // end quantity loop
-
- $return['success'] = true;
- $return['devices'] = $device;
-
- $return['stats'] = $event->getEventStats();
-
- return response()->json($return);
- }
-
- public function ajaxEdit(Request $request, $id)
- {
- $category = $request->input('category');
- $brand = $request->input('brand');
- $item_type = $request->input('item_type');
- $model = $request->input('model');
- $age = $request->filled('age') ? $request->input('age',0) : 0;
- $problem = $request->input('problem');
- $notes = $request->input('notes');
- $repair_status = $request->input('repair_status');
- $barrier = $request->input('barrier');
- $repair_details = $request->input('repair_details');
- $spare_parts = $request->input('spare_parts');
- $event_id = $request->input('event_id');
- $wiki = $request->input('wiki');
- $estimate = $request->filled('estimate') ? $request->input('estimate', 0) : 0;
-
- $request->validate([
- 'age' => 'nullable|numeric|max:500'
- ]);
-
- if (empty($repair_status)) { //Override
- $repair_status = 0;
- }
-
- if ($repair_status != 2) { //Override
- $repair_details = 0;
- }
-
- if (Fixometer::userHasEditEventsDevicesPermission($event_id)) {
- if ($repair_details == 1) {
- $more_time_needed = 1;
- } else {
- $more_time_needed = 0;
- }
-
- if ($repair_details == 2) {
- $professional_help = 1;
- } else {
- $professional_help = 0;
- }
-
- if ($repair_details == 3) {
- $do_it_yourself = 1;
- } else {
- $do_it_yourself = 0;
- }
-
- if ($spare_parts == 3) { // Third party
- $spare_parts = 1;
- $parts_provider = 2;
- } elseif ($spare_parts == 1) { // Manufacturer
- $spare_parts = 1;
- $parts_provider = 1;
- } elseif ($spare_parts == 2) { // Not needed
- $spare_parts = 2;
- $parts_provider = null;
- } elseif ($spare_parts == 4) { // Historical data, resets spare parts to 1 but keeps parts provider as null
- $spare_parts = 1;
- $parts_provider = null;
- } else {
- $parts_provider = null;
- }
-
- if (! isset($barrier)) {
- $barrier = null;
- } elseif (in_array(1, $barrier) || in_array(2, $barrier)) { // 'Spare parts not available' or 'spare parts too expensive' selected
- $spare_parts = 1;
- } elseif (count($barrier) > 0) {
- $spare_parts = 2;
- }
-
- $Device = Device::find($id);
-
- $Device->update([
- 'category' => $category,
- 'brand' => $brand,
- 'item_type' => $item_type,
- 'model' => $model,
- 'age' => $age,
- 'problem' => $problem,
- 'notes' => $notes,
- 'spare_parts' => $spare_parts,
- 'parts_provider' => $parts_provider,
- 'repair_status' => $repair_status,
- 'more_time_needed' => $more_time_needed,
- 'professional_help' => $professional_help,
- 'do_it_yourself' => $do_it_yourself,
- 'wiki' => $wiki,
- 'estimate' => $estimate,
- ]);
-
- // Update barriers
- if (isset($barrier) && ! empty($barrier) && $repair_status == 3) { // Only sync when repair status is end-of-life
- $Device->barriers()->sync($barrier);
- } else {
- $Device->barriers()->sync([]);
- }
-
- $event = Party::find($event_id);
- event(new DeviceCreatedOrUpdated($Device));
-
- $stats = $event->getEventStats();
- $data['stats'] = $stats;
- $data['success'] = 'Device updated!';
-
- // Expand a few things so that the devices are returned with the same information that existing
- // ones are returned in the view blade.
- $device = Device::find($id);
- $device->idevents = $device->event;
- $device->category = $device->deviceCategory;
- $device->shortProblem = $device->getShortProblem();
- $device->images = $device->getImages();
-
- $barriers = [];
-
- foreach ($device->barriers as $b) {
- $barriers[] = $b->id;
- }
-
- $device->barrier = $barriers;
-
- $data['device'] = $device;
-
- return response()->json($data);
- }
- }
-
- public function delete(Request $request, $id)
- {
- $user = Auth::user();
-
- $device = Device::find($id);
-
- if ($device) {
- $eventId = $device->event;
- $is_attending = EventsUsers::where('event', $device->event)->where('user', Auth::id())->first();
- $is_attending = is_object($is_attending) && $is_attending->status == 1;
-
- if (Fixometer::hasRole($user, 'Administrator') ||
- Fixometer::userHasEditPartyPermission($eventId, $user->id) ||
- $is_attending
- ) {
- $device->delete();
-
- if ($request->ajax()) {
- $event = Party::find($eventId);
- $stats = $event->getEventStats();
-
- return response()->json([
- 'success' => true,
- 'stats' => $stats,
- ]);
- }
-
- return redirect('/party/view/'.$eventId)->with('success', __('devices.device_delete_sucess'));
- }
- }
-
- if ($request->ajax()) {
- return response()->json(['success' => false]);
- }
-
- \Sentry\CaptureMessage(__('devices.device_delete_permissions'));
- return redirect('/party/view/'.$eventId)->with('warning', __('devices.device_delete_permissions'));
- }
-
public function imageUpload(Request $request, $id)
{
try {
@@ -401,7 +77,7 @@ public function imageUpload(Request $request, $id)
if ($id > 0) {
// We are adding a photo to an existing device.
$fn = $file->upload('file', 'image', $id, env('TBL_DEVICES'), true, false, true);
- $device = Device::find($id);
+ $device = Device::findOrFail($id);
$images = $device->getImages();
} else {
// We are adding a photo for a device that hasn't yet been added. Upload the file. We will add
diff --git a/app/Http/Resources/Category.php b/app/Http/Resources/Category.php
new file mode 100644
index 0000000000..fcd8d1ac13
--- /dev/null
+++ b/app/Http/Resources/Category.php
@@ -0,0 +1,52 @@
+ $this->idcategories,
+ 'name' => $this->name,
+ 'powered' => $this->powered,
+ ];
+ }
+}
diff --git a/app/Http/Resources/Device.php b/app/Http/Resources/Device.php
new file mode 100644
index 0000000000..2f7d678324
--- /dev/null
+++ b/app/Http/Resources/Device.php
@@ -0,0 +1,281 @@
+event);
+ $group = $event ? \App\Group::find($event->group) : NULL;
+
+ $ret = [
+ 'id' => intval($this->iddevices),
+ 'eventid' => intval($this->event),
+ 'eventtitle' => $event ? $event->title : NULL,
+ 'groupid' => $event ? intval($event->group) : NULL,
+ 'groupname' => $group ? $group->name : NULL,
+ 'category' => intval($this->category),
+ 'item_type' => $this->item_type,
+ 'brand' => $this->brand,
+ 'model' => $this->model,
+ 'age' => floatval($this->age),
+ 'estimate' => floatval($this->estimate),
+ 'problem' => $this->problem,
+ 'short_problem' => $this->getShortProblem(),
+ 'notes' => $this->notes,
+ 'created_at' => $this->created_at->toIso8601String(),
+ 'updated_at' => $this->created_at->toIso8601String(),
+ 'reference' => $this->reference,
+ ];
+
+ // Our database has a slightly complex structure for historical reasons, so we need to map some underlying
+ // fields to simpler values to keep the API clean.
+ //
+ // There is mirror code in API\DeviceController.
+ switch ($this->repair_status) {
+ case \App\Device::REPAIR_STATUS_FIXED:
+ $ret['repair_status'] = \App\Device::REPAIR_STATUS_FIXED_STR;
+ break;
+ case \App\Device::REPAIR_STATUS_REPAIRABLE:
+ $ret['repair_status'] = \App\Device::REPAIR_STATUS_REPAIRABLE_STR;
+ break;
+ case \App\Device::REPAIR_STATUS_ENDOFLIFE:
+ $ret['repair_status'] = \App\Device::REPAIR_STATUS_ENDOFLIFE_STR;
+ break;
+ }
+
+ if ($this->more_time_needed) {
+ $ret['next_steps'] = \App\Device::NEXT_STEPS_MORE_TIME_NEEDED_STR;
+ } else if ($this->professional_help) {
+ $ret['next_steps'] = \App\Device::NEXT_STEPS_PROFESSIONAL_HELP_STR;
+ } else if ($this->do_it_yourself) {
+ $ret['next_steps'] = \App\Device::NEXT_STEPS_DO_IT_YOURSELF_STR;
+ }
+
+ if ($this->spare_parts === \App\Device::SPARE_PARTS_NOT_NEEDED) {
+ $ret['spare_parts'] = \App\Device::PARTS_PROVIDER_NO_STR;
+ } else if ($this->spare_parts === null) {
+ $ret['spare_parts'] = null;
+ } else {
+ if ($this->parts_provider === \App\Device::PARTS_PROVIDER_MANUFACTURER) {
+ $ret['spare_parts'] = \App\Device::PARTS_PROVIDER_MANUFACTURER_STR;
+ } else if ($this->parts_provider === \App\Device::PARTS_PROVIDER_THIRD_PARTY) {
+ $ret['spare_parts'] = \App\Device::PARTS_PROVIDER_THIRD_PARTY_STR;
+ }
+ }
+
+ if ($this->professional_help) {
+ $ret['next_steps'] = \App\Device::NEXT_STEPS_PROFESSIONAL_HELP_STR;
+ } else if ($this->do_it_yourself) {
+ $ret['next_steps'] = \App\Device::NEXT_STEPS_DO_IT_YOURSELF_STR;
+ } else if ($this->more_time_needed) {
+ $ret['next_steps'] = \App\Device::NEXT_STEPS_MORE_TIME_NEEDED_STR;
+ } else {
+ $ret['next_steps'] = null;
+ }
+
+ // The underlying DB might have multiple barriers, but we only support one across the API.
+ foreach ($this->resource->barriers as $barrier) {
+ $ret['barrier'] = $barrier->barrier;
+ break;
+ }
+
+ $category = \App\Category::find($this->category);
+ $ret['category']= \App\Http\Resources\Category::make($category);
+
+ $images = $this->resource->getImages();
+ $ret['images'] = \App\Http\Resources\Image::collection($images);
+
+ return $ret;
+ }
+}
diff --git a/app/Http/Resources/Image.php b/app/Http/Resources/Image.php
new file mode 100644
index 0000000000..436b508a52
--- /dev/null
+++ b/app/Http/Resources/Image.php
@@ -0,0 +1,45 @@
+ $this->idimages,
+ 'idxref' => $this->idxref,
+ 'path' => $this->path
+ ];
+ }
+}
diff --git a/app/Http/Resources/Item.php b/app/Http/Resources/Item.php
index 2e5a80aae7..fd9a870d2b 100644
--- a/app/Http/Resources/Item.php
+++ b/app/Http/Resources/Item.php
@@ -8,7 +8,7 @@
* @OA\Schema(
* title="Item",
* schema="Item",
- * description="An item which can be specified in a device",
+ * description="An item which can be specified in a Device",
* @OA\Property(
* property="type",
* title="type",
diff --git a/app/Party.php b/app/Party.php
index cbe94b955e..cd174cdd54 100644
--- a/app/Party.php
+++ b/app/Party.php
@@ -47,7 +47,7 @@ class Party extends Model implements Auditable
'user_id',
'network_data',
];
- protected $hidden = ['created_at', 'deleted_at', 'frequency', 'group', 'group', 'user_id', 'wordpress_post_id', 'cancelled', 'devices_updated_at'];
+ protected $hidden = ['created_at', 'deleted_at', 'frequency', 'group', 'user_id', 'wordpress_post_id', 'cancelled', 'devices_updated_at'];
// Eager-loading the group reduces N+1 queries.
protected $with = 'theGroup';
diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php
index 159764bcc8..adb0175cd4 100644
--- a/app/Providers/RouteServiceProvider.php
+++ b/app/Providers/RouteServiceProvider.php
@@ -69,7 +69,7 @@ public function boot()
protected function configureRateLimiting()
{
RateLimiter::for('api', function (Request $request) {
- return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
+ return Limit::perMinute(300)->by($request->user()?->id ?: $request->ip());
});
}
}
diff --git a/database/migrations/2025_01_07_152513_device_reference.php b/database/migrations/2025_01_07_152513_device_reference.php
new file mode 100644
index 0000000000..1019dff1b8
--- /dev/null
+++ b/database/migrations/2025_01_07_152513_device_reference.php
@@ -0,0 +1,32 @@
+string('reference')->nullable();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::table('devices', function (Blueprint $table) {
+ $table->dropColumn('reference');
+ });
+ }
+};
diff --git a/lang/de/partials.php b/lang/de/partials.php
index 2bad1a26c3..b8e9d53625 100644
--- a/lang/de/partials.php
+++ b/lang/de/partials.php
@@ -51,11 +51,9 @@
'least_repaired' => 'Least repaired',
'most_repaired' => 'Most repaired',
'most_seen' => 'Most seen',
- 'solution_text' => 'Could the solution comments help Restarters working on a similar device in future? Or is it a fun case study?',
'no_devices_added' => 'No devices added',
'add_a_device' => 'Add a device',
'event_requires_moderation_by_an_admin' => 'Event requires moderation by an admin',
'save' => 'Save item',
- 'solution_text2' => 'Interesting case study to share?',
'cancel' => 'Cancel',
];
diff --git a/lang/en/devices.php b/lang/en/devices.php
index a0738d7f20..5410cddd46 100644
--- a/lang/en/devices.php
+++ b/lang/en/devices.php
@@ -66,7 +66,6 @@
'assessment' => 'Assessment',
'item_and_repair_info' => 'Item & Repair Info',
'search_assessment_comments' => 'Assessment',
- 'interesting_case_study' => 'Interesting case study',
'tooltip_type' => 'Add as much information about the type of item here as you can (e.g. `Denim jeans` or ‘Sofa’)',
'add_data_group' => 'Please select a group',
'add_data_event' => 'Please select an event',
@@ -79,6 +78,6 @@
'image_delete_success' => 'Thank you, the image has been deleted',
'image_delete_error' => 'Sorry, but the image can\'t be deleted',
'image_upload_error' => 'fail - image could not be uploaded',
- 'device_delete_sucess' => 'Device has been deleted!',
- 'device_delete_permissions' => 'You do not have the right permissions for deleting a device.',
+ 'reference' => 'Reference',
+ 'tooltip_reference' => 'You can optionally record your own reference ID for this item, to cross-reference it to other software tools you are using.',
];
diff --git a/lang/en/partials.php b/lang/en/partials.php
index 1f887ebcd7..b0d07ba9f8 100644
--- a/lang/en/partials.php
+++ b/lang/en/partials.php
@@ -52,7 +52,6 @@
'least_repaired' => 'Least repaired',
'most_repaired' => 'Most repaired',
'most_seen' => 'Most seen',
- 'solution_text' => 'Could the solution comments help volunteers working on a similar device in future? Or is it a fun case study?',
'no_devices_added' => 'No devices added',
'add_a_device' => 'Add a device',
'event_requires_moderation_by_an_admin' => 'Event requires moderation by an admin',
@@ -60,10 +59,9 @@
'hot_topics' => 'Hot topics',
'hot_topics_text' => 'Join in on the latest hot topics on repair at Restarters Talk.',
'hot_topics_link' => 'All weekly hot topics',
- 'choose_barriers' => 'Choose barriers to repair',
+ 'choose_barriers' => 'Choose main barrier to repair',
'add_device_powered' => 'Add Powered Item',
'add_device_unpowered' => 'Add Unpowered Item',
- 'solution_text2' => 'Interesting case study to share?',
'emissions_equivalent_consume_low' => "that's like growing :value tree seedling for 10 years|that's like growing :value tree seedlings for 10 years",
'emissions_equivalent_consume_high' => "that's like planting around :value hectare of trees|that's like planting around :value hectares of trees",
'emissions_equivalent_consume_low_explanation' => 'Medium growth coniferous or deciduous trees, planted in an urban setting and grown for 10 years.',
diff --git a/lang/fr-BE/devices.php b/lang/fr-BE/devices.php
index 5798fdc0fa..286c833b31 100644
--- a/lang/fr-BE/devices.php
+++ b/lang/fr-BE/devices.php
@@ -63,7 +63,6 @@
'status' => 'Statut',
'latest_data' => 'Dernières données',
'assessment' => 'Evaluation',
- 'interesting_case_study' => 'Cas d\'étude intéressant',
'item_and_repair_info' => 'Appareils et informations de réparation',
'search_assessment_comments' => 'Evaluation',
'table_intro' => 'Cliquez sur la ligne pour plus de détails. Cliquez sur l\'en-tête d\'une colonne pour trier par cette colonne - cliquez à nouveau pour inverser l\'ordre de tri.',
@@ -79,6 +78,6 @@
'image_delete_success' => 'Merci, l\'image a été supprimée',
'image_delete_error' => 'Désolé, mais l\'image ne peut pas être supprimée.',
'image_upload_error' => 'fail - l\'image n\'a pas pu être téléchargée',
- 'device_delete_sucess' => 'L\'appareil a été supprimé!',
- 'device_delete_permissions' => 'Vous n\'avez pas les autorisations nécessaires pour supprimer un appareil.',
+ 'reference' => 'Référence',
+ 'tooltip_reference' => 'Vous pouvez éventuellement enregistrer votre propre identifiant de référence pour cet élément, afin de le recouper avec d\'autres outils logiciels que vous utilisez.',
];
diff --git a/lang/fr-BE/partials.php b/lang/fr-BE/partials.php
index 581e4afcb8..f621ec3351 100644
--- a/lang/fr-BE/partials.php
+++ b/lang/fr-BE/partials.php
@@ -52,7 +52,6 @@
'least_repaired' => 'Dernier réparé',
'most_repaired' => 'Les plus réparés',
'most_seen' => 'Les plus vus',
- 'solution_text' => 'Est-ce que la solution en commentaire aide un réparateur à travailler sur un cas similiaire? Ou est-ce une étude de cas amusante?',
'no_devices_added' => 'Pas d\'appareils ajoutés',
'add_a_device' => 'Ajouter un appareil',
'event_requires_moderation_by_an_admin' => 'L\'événement nécessite l\'approbation d\'un administrateur',
@@ -60,8 +59,7 @@
'hot_topics' => 'Sujets d\'actualité',
'hot_topics_link' => 'Tous les derniers sujets d\'actualités',
'hot_topics_text' => 'Prenez part au dernier sujet d\'actualité de réparation sur Restarters Talk',
- 'choose_barriers' => 'Choisir les freins à la réparation',
- 'solution_text2' => 'Cas d\'étude intéressant à partager?',
+ 'choose_barriers' => 'Choisir l\'obstacle principal à la réparation',
'quantity' => 'Quantité',
'cancel' => 'Annuler',
'powered_only' => '(calculé pour les objets électriques uniquement)',
diff --git a/lang/fr/devices.php b/lang/fr/devices.php
index 5798fdc0fa..8eb95e04b6 100644
--- a/lang/fr/devices.php
+++ b/lang/fr/devices.php
@@ -63,7 +63,6 @@
'status' => 'Statut',
'latest_data' => 'Dernières données',
'assessment' => 'Evaluation',
- 'interesting_case_study' => 'Cas d\'étude intéressant',
'item_and_repair_info' => 'Appareils et informations de réparation',
'search_assessment_comments' => 'Evaluation',
'table_intro' => 'Cliquez sur la ligne pour plus de détails. Cliquez sur l\'en-tête d\'une colonne pour trier par cette colonne - cliquez à nouveau pour inverser l\'ordre de tri.',
@@ -79,6 +78,6 @@
'image_delete_success' => 'Merci, l\'image a été supprimée',
'image_delete_error' => 'Désolé, mais l\'image ne peut pas être supprimée.',
'image_upload_error' => 'fail - l\'image n\'a pas pu être téléchargée',
- 'device_delete_sucess' => 'L\'appareil a été supprimé!',
- 'device_delete_permissions' => 'Vous n\'avez pas les autorisations nécessaires pour supprimer un appareil.',
+ 'reference' => 'Référence',
+ 'tooltip_reference' => 'Vous pouvez éventuellement enregistrer votre propre identifiant de référence pour cet élément, afin de le recouper avec d\'autres outils logiciels que vous utilisez.',
];
diff --git a/lang/fr/partials.php b/lang/fr/partials.php
index 581e4afcb8..f621ec3351 100644
--- a/lang/fr/partials.php
+++ b/lang/fr/partials.php
@@ -52,7 +52,6 @@
'least_repaired' => 'Dernier réparé',
'most_repaired' => 'Les plus réparés',
'most_seen' => 'Les plus vus',
- 'solution_text' => 'Est-ce que la solution en commentaire aide un réparateur à travailler sur un cas similiaire? Ou est-ce une étude de cas amusante?',
'no_devices_added' => 'Pas d\'appareils ajoutés',
'add_a_device' => 'Ajouter un appareil',
'event_requires_moderation_by_an_admin' => 'L\'événement nécessite l\'approbation d\'un administrateur',
@@ -60,8 +59,7 @@
'hot_topics' => 'Sujets d\'actualité',
'hot_topics_link' => 'Tous les derniers sujets d\'actualités',
'hot_topics_text' => 'Prenez part au dernier sujet d\'actualité de réparation sur Restarters Talk',
- 'choose_barriers' => 'Choisir les freins à la réparation',
- 'solution_text2' => 'Cas d\'étude intéressant à partager?',
+ 'choose_barriers' => 'Choisir l\'obstacle principal à la réparation',
'quantity' => 'Quantité',
'cancel' => 'Annuler',
'powered_only' => '(calculé pour les objets électriques uniquement)',
diff --git a/lang/it/partials.php b/lang/it/partials.php
index fea5cdc7b2..8058388cb6 100644
--- a/lang/it/partials.php
+++ b/lang/it/partials.php
@@ -51,7 +51,6 @@
'least_repaired' => 'Meno riparato',
'most_repaired' => 'Piu\' riparato',
'most_seen' => 'Piu\' visto',
- 'solution_text' => 'I commenti della soluzione potrebbero aiutare i Restarters a lavorare su un dispositivo simile in futuro? O è un qualcosa di divertente?',
'no_devices_added' => 'Nessun dispositivo aggiunto',
'add_a_device' => 'Aggiungi un dispositivo',
'event_requires_moderation_by_an_admin' => 'L\'evento richiede la moderazione di un
@@ -60,6 +59,5 @@
'hot_topics' => 'Argomenti piu\' seguiti',
'hot_topics_link' => 'Argomenti piu\' seguiti della settimana',
'hot_topics_text' => 'Unisciti alla conversazione su gli argomenti piu\' seguiti della settimana',
- 'solution_text2' => 'Interesting case study to share?',
'cancel' => 'Cancel',
];
diff --git a/lang/nl-BE/partials.php b/lang/nl-BE/partials.php
index c74258a492..4e76f1ee78 100644
--- a/lang/nl-BE/partials.php
+++ b/lang/nl-BE/partials.php
@@ -46,7 +46,6 @@
'save' => 'Toestel opslaan',
'see_all_events' => 'Alle activiteiten bekijken',
'see_more_posts' => 'Meer posts bekijken',
- 'solution_text' => 'Is je oplossing nuttig voor andere Restarters die een gelijkaardig toestel proberen te herstellen? Of is het een leuke case study?',
'update' => 'Updaten',
'view_the_materials' => 'Tips en info bekijken',
'welcome_text' => 'We geven info en tips over het organiseren van repareer activiteiten en helpen je om je competenties te delen.',
@@ -58,6 +57,5 @@
'yes_third_party' => 'Ja - van een derde partij',
'your_recent_events' => 'Je meest recente activiteiten',
'your_recent_events_txt1' => 'Dit zijn activiteiten waarop je antwoordde of waaraan je werd toegevoegd door een organisator',
- 'solution_text2' => 'Interesting case study to share?',
'cancel' => 'Cancel',
];
diff --git a/lang/no/partials.php b/lang/no/partials.php
index 28f0fef04a..39cc83be4b 100644
--- a/lang/no/partials.php
+++ b/lang/no/partials.php
@@ -51,11 +51,9 @@
'least_repaired' => 'Least repaired',
'most_repaired' => 'Most repaired',
'most_seen' => 'Most seen',
- 'solution_text' => 'Could the solution comments help Restarters working on a similar device in future? Or is it a fun case study?',
'no_devices_added' => 'No devices added',
'add_a_device' => 'Add a device',
'event_requires_moderation_by_an_admin' => 'Event requires moderation by an admin',
'save' => 'Save item',
- 'solution_text2' => 'Interesting case study to share?',
'cancel' => 'Cancel',
];
diff --git a/resources/js/components/DeviceAge.vue b/resources/js/components/DeviceAge.vue
index 4bffe7035b..90aceebe61 100644
--- a/resources/js/components/DeviceAge.vue
+++ b/resources/js/components/DeviceAge.vue
@@ -3,7 +3,7 @@
- {{ __('devices.title_repair') }}
-