diff --git a/admin/event-edit.php b/admin/event-edit.php
index 86f3259..466c3bf 100644
--- a/admin/event-edit.php
+++ b/admin/event-edit.php
@@ -1,666 +1,703 @@
 <?php
 # Linux Day Torino website
 # Copyright (C) 2016, 2017, 2018, 2019, 2020 Valerio Bozzolan, Linux Day Torino
 #
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Affero General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Affero General Public License for more details.
 #
 # You should have received a copy of the GNU Affero General Public License
 # along with this program. If not, see <http://www.gnu.org/licenses/>.
 
 /*
  * Event edit
  *
  * From this page you can create/edit an User and assign some skills/interests etc.
  */
 
 // load configurations and framework
 require 'load.php';
 
 // inherit the Conference or specify one
 $conference_uid = $_GET['conference_uid'] ?? $_POST['conference_uid'] ?? CURRENT_CONFERENCE_UID;
 
 // check if the Conference exists
 $conference = ( new QueryConference() )
 	->whereConferenceUID( $conference_uid )
 	->queryRow();
 
 // no Conference no party
 if( !$conference ) {
 	error( "missing conference with UID $conferene_uid" );
 	die_with_404();
 }
 
 // retrieve the Event (if existing)
 $event = null;
 if( isset( $_GET['id'] ) ) {
 
 	// no Event no party
 	$event = ( new QueryEvent() )
 		->whereConference( $conference )
 		->joinConference()
 		->joinChapter( 'LEFT' )
 		->whereEventID( $_GET['id'] )
 		->queryRow();
 
 	// no Event no party
 	if( !$event ) {
 		die_with_404();
 	}
 
 	// no editable no party
 	if( !$event->isEventEditable() ) {
 		missing_privileges();
 	}
 } else {
 	// check if there are permissions to add event
 	if( !has_permission( 'add-event' ) ) {
 		missing_privileges();
 	}
 }
 
 $warning = null;
 
 // check if the user submitted a form
 // check which one
 if( $_POST ) {
 
 	// the user is submitting the save form
 	if( is_action( 'save-event' ) ) {
 
 		$conference_ID = $conference->getConferenceID();
 
 		$data = [];
 		$data[] = new DBCol( Event::TITLE,       $_POST['title'],       's' );
 		$data[] = new DBCol( Event::UID,         $_POST['uid'],         's' );
 		$data[] = new DBCol( Event::LANGUAGE,    $_POST['language'],    's' );
 		$data[] = new DBCol( Event::SUBTITLE,    $_POST['subtitle'],    's' );
 		$data[] = new DBCol( Event::START,       $_POST['start'],       's' );
 		$data[] = new DBCol( Event::END,         $_POST['end'],         's' );
 		$data[] = new DBCol( Event::EXTERNAL_URL,$_POST['url'],         's' );
 		$data[] = new DBCol( Event::ABORTED,     $_POST['aborted'],     'd' );
 		$data[] = new DBCol( Event::IMAGE,       $_POST['image'],       'snull' );
 		$data[] = new DBCol( Chapter::ID,        $_POST['chapter'],     'd' );
 		$data[] = new DBCol( Room::ID,           $_POST['room'],        'd' );
 		$data[] = new DBCol( Track::ID,          $_POST['track'],       'd' );
 		$data[] = new DBCol( Conference::ID,     $conference_ID,        'd' );
 
 		// for each language save the fields
 		foreach( all_languages() as $lang ) {
 			foreach( Event::fields_i18n() as $i18n_column => $label ) {
 				// generic column name in this language
 				$field = $i18n_column . '_' . $lang->getISO();
 
 				// sent column value
 				$value = $_POST[ $field ] ?? null;
 
 				// prepare to be saved
 				$data[] = new DBCol( $field, $value, 'snull' );
 			}
 		}
 
 		// convert empty strings to NULL, if possible
 		foreach( $data as $row ) {
 			$row->promoteNULL();
 		}
 
 		if( $event ) {
 			// update the existing Event
 			( new QueryEvent() )
 				->whereEvent( $event )
 				->update( $data );
 		} else {
 			// insert a new Event
 			Event::factory()
 				->insertRow( $data );
 		}
 
 		$id = $event ? $event->getEventID() : last_inserted_ID();
 
 		// get the updated Event
 		$event = FullEvent::factory()
 			->whereInt( Event::ID, $id )
 			->queryRow();
 
 		// POST-redirect-GET
 		http_redirect( $event->getEventEditURL(), 303 );
 	}
 
 	/**
 	 * Change the Image
 	 */
 	if( $event && is_action( 'change-image' ) ) {
 
 		// prepare the image uploader
 		$image = new FileUploader( 'image', [
 			'category'          => 'image',
 			'override-filename' => "event-" . $event->getEventUID(),
 		] );
 
 		// prepare the image pathnames
 		$img_url  =                $event->getConferenceUID() . _ .  'images';
 		$img_path = ABSPATH . __ . $event->getConferenceUID() . __ . 'images';
 
 		// really upload that shitty image somewhere
 		if( $image->fileChoosed() ) {
 			$ok = $image->uploadTo( $img_path, $status, $filename, $ext );
 			if( $ok ) {
 
 				// now update
 				( new QueryEvent() )
 					->whereEvent( $event )
 					->update( [
 						'event_img' => $img_url . "/$filename.$ext",
 					] );
 
 				// POST-redirect-GET
 				http_redirect( $event->getFullEventEditURL(), 303 );
 
 			} else {
 				$warning = $image->getErrorMessage();
 			}
 		}
 	}
 
 	/*
 	 * Add the user
 	 */
 	if( $event && is_action( 'add-user' ) && isset( $_POST['user'] ) ) {
 		// Add user
 
 		$user = User::factoryFromUID( $_POST['user'] )
 			->select( User::ID )
 			->queryRow();
 
 		if( $user ) {
 			( new QueryEventUser() )
 				->whereEvent( $event )
 				->whereUser(  $user  )
 				->delete();
 
 			( new QueryEventUser() )->insertRow( [
 				new DBCol( Event::ID, $event->getEventID(), 'd' ),
 				new DBCol( User ::ID, $user->getUserID(),   'd' ),
 				new DBCol( EventUser::ORDER, 0,             'd' ),
 			] );
 		}
 	}
 
 	/**
 	 * Update an user order
 	 */
 	if( $event && is_action( 'update-user' ) && isset( $_POST['user'] ) ) {
 
 		$user = User::factoryFromUID( $_POST['user'] )
 			->select( User::ID )
 			->queryRow();
 
 		if( $user ) {
 			if ( !empty( $_POST['delete'] ) ) {
 
 				// delete user
 				( new QueryEventUser() )
 					->whereEvent( $event )
 					->whereUser( $user )
 					->delete();
 
 			} elseif( isset( $_POST['order'] ) ) {
 
 				// change order
 				( new QueryEventUser() )
 					->whereEvent( $event )
 					->whereUser( $user )
 					->update( [
 						new DBCol( EventUser::ORDER, $_POST['order'], 'd' )
 					] );
 			}
 		}
 	}
 
 	// post -> redirect -> get (no: it hide errors)
 	// http_redirect( $_SERVER[ 'REQUEST_URI' ], 303 );
 }
 
+// Event's Sharable(s)
+$sharables = [];
+
 if( $event ) {
+
+	// query all the Sharable(s) related to this Event
+	$sharables =
+		( new QuerySharable() )
+			->whereEvent( $event )
+			->queryGenerator();
+
 	Header::spawn( null, [
 		'title' => sprintf(
 			__("Modifica %s: %s"),
 			$event->getChapterName(),
 			$event->getEventTitle()
 		),
 	] );
 } else {
 	Header::spawn( null, [
 		'title' => sprintf(
 			__( "Aggiungi %s" ),
 			__( "Evento" )
 		),
 	] );
 }
 
 ?>
 
 	<?php if( $warning ): ?>
 		<div class="card-panel yellow"><?= esc_html( $warning ) ?></div>
 	<?php endif ?>
 
 	<p><?= HTML::a(
 		$conference->getConferenceURL(),
 		esc_html( $conference->getConferenceTitle() ) . icon( 'home', 'left' )
 	) ?></p>
 
 	<?php if( $event && $event->hasEventPermalink() ): ?>
 		<p><?= HTML::a(
 			// href
 			$event->getEventURL(),
 
 			// text
 			__( "Vedi" ) . icon( 'account_box', 'left' )
 		) ?></p>
 	<?php endif ?>
 
 	<form method="post">
 		<?php form_action( 'save-event' ) ?>
 
 		<div class="row">
 
 			<div class="col s12 m4 l3">
 				<div class="card-panel">
 					<label for="event-title"><?= __( "Titolo" ) ?></label>
 					<input type="text" name="title" id="event-title" required<?php
 						if( $event ) {
 							echo value( $event->get( Event::TITLE ) );
 						}
 					?> />
 				</div>
 			</div>
 
 			<div class="col s12 m4 l3">
 				<div class="card-panel">
 					<label for="event-uid"><?= __( "Codice" ) ?></label>
 					<input type="text" name="uid" id="event-uid" required<?php
 						if( $event ) {
 							echo value( $event->get( Event::UID ) );
 						}
 					?> />
 				</div>
 			</div>
 
 			<div class="col s12 m4 l3">
 				<div class="card-panel">
 					<label for="event-subtitle"><?= __( "Sottotitolo" ) ?></label>
 					<input type="text" name="subtitle" id="event-subtitle"<?php
 						if( $event ) {
 							echo value( $event->get( Event::SUBTITLE ) );
 						}
 					?> />
 				</div>
 			</div>
 
 			<div class="col s12 m4 l3">
 				<div class="card-panel">
 					<label for="event-url"><?= __( "URL" ) ?></label>
 					<input type="text" name="url" id="event-url"<?php
 						if( $event ) {
 							echo value( $event->get( Event::EXTERNAL_URL ) );
 						}
 					?> />
 				</div>
 			</div>
 
 			<div class="col s12 m4 l3">
 				<div class="card-panel">
 					<label for="event-language"><?= __( "Lingua" ) ?></label>
 					<input type="text" name="language" id="event-language" maxlenght="2"<?php
 						if( $event ) {
 							echo value( $event->get( Event::LANGUAGE ) );
 						}
 					?> />
 				</div>
 			</div>
 
 		</div>
 
 		<div class="row">
 
 			<!-- chapters -->
 			<div class="col s12 m4 l3">
 				<div class="card-panel">
 					<label for="chapter"><?= __( "Capitolo" ) ?></label>
 					<select name="chapter">
 						<?php
 							// get every chapter
 							$chapters =
 								Chapter::factory()
 									->orderBy( Chapter::NAME )
 									->queryGenerator();
 
 							// generate select options
 							foreach( $chapters as $chapter ) {
 								$option = ( new HTML( 'option' ) )
 									->setText( esc_html( $chapter->getChapterName() ) )
 									->setAttr( 'value',  $chapter->getChapterID() );
 
 								// eventually select this chapter
 								$selected = false;
 
 								if( $event && $event->has( Chapter::ID ) ) {
 									$selected = $event->getChapterID() === $chapter->getChapterID();
 								} elseif( isset( $_GET['chapter'] ) ) {
 									$selected = $_GET['chapter'] === $chapter->getChapterUID();
 								}
 
 								if( $selected ) {
 										$option->setAttr( 'selected', 'selected' );
 								}
 
 								echo $option->render();
 							}
 						?>
 					</select>
 				</div>
 			</div>
 			<!-- /chapters -->
 
 			<!-- tracks -->
 			<div class="col s12 m4 l3">
 				<div class="card-panel">
 					<label for="track"><?= __( "Traccia" ) ?></label>
 					<select name="track">
 						<?php
 							// select all the available tracks for this Location
 							$tracks =
 								Track::factory()
 									->orderBy( Track::NAME )
 									->queryGenerator();
 
 							// generate a select option for each track
 							foreach( $tracks as $track ) {
 								$option = ( new HTML( 'option' ) )
 									->setText( esc_html( $track->getTrackName() ) )
 									->setAttr( 'value', $track->getTrackID() );
 
 								// eventually auto-select this track
 								$selected = false;
 								if( $event && $event->has( Track::ID ) ) {
 									$selected = $event->getTrackID() === $track->getTrackID();
 								} elseif( isset( $_GET['track'] ) ) {
 									$selected = $_GET['track'] === $track->getTrackUID();
 								}
 
 								if( $selected ) {
 										$option->setAttr( 'selected', 'selected' );
 								}
 
 								echo $option->render();
 							}
 						?>
 					</select>
 				</div>
 			</div>
 			<!-- /tracks -->
 
 			<!-- rooms -->
 			<div class="col s12 m4 l3">
 				<div class="card-panel">
 					<label for="room"><?= __( "Stanza" ) ?></label>
 					<select name="room">
 						<?php
 							// select all the available rooms for this Location
 							$rooms =
 								Room::factory()
 									->whereInt( Location::ID, $conference->getLocationID() )
 									->orderBy( Room::NAME )
 									->queryGenerator();
 
 							// generate a select option for each room
 							foreach( $rooms as $room ) {
 								$option = ( new HTML( 'option' ) )
 									->setText( esc_html( $room->getRoomName() ) )
 									->setAttr( 'value', $room->getRoomID() );
 
 								// eventually auto-select this room
 								$selected = false;
 								if( $event && $event->has( Room::ID ) ) {
 									$selected = $event->getRoomID() === $room->getRoomID();
 								} elseif( isset( $_GET['room'] ) ) {
 									$selected = $_GET['room'] === $room->getRoomUID();
 								}
 
 								if( $selected ) {
 										$option->setAttr( 'selected', 'selected' );
 								}
 
 								echo $option->render();
 							}
 						?>
 					</select>
 				</div>
 			</div>
 			<!-- /rooms -->
 
 		</div>
 
 
 		<div class="row">
 
 			<div class="col s12 m4 l3">
 				<div class="card-panel">
 					<label for="event-start"><?= __( "Inizio" ) ?></label>
 					<input type="text" name="start" required placeholder="Y-m-d H:i:s"<?php
 						if( $event ) {
 							echo value( $event->getEventStart()->format( 'Y-m-d H:i:s' ) );
 						} elseif( isset( $_GET['start'] ) ) {
 							echo value( $_GET['start'] );
 						}
 					?> />
 				</div>
 			</div>
 
 			<div class="col s12 m4 l3">
 				<div class="card-panel">
 					<label for="event-end"><?= __( "Fine" ) ?></label>
 					<input type="text" name="end" required placeholder="Y-m-d H:i:s"<?php
 						if( $event ) {
 							echo value( $event->getEventEnd()->format( 'Y-m-d H:i:s' ) );
 						} elseif( isset( $_GET['end'] ) ) {
 							echo value( $_GET['end'] );
 						}
 					?> />
 				</div>
 			</div>
 
 			<div class="col s12 m4 l3">
 				<div class="card-panel">
 					<label for="event-aborted"><?= __( "Annullato" ) ?></label>
 					<select name="aborted">
 						<option value="0"<?= selected( !$event || !$event->isEventAborted() ) ?>><?= __( "No"  ) ?></option>
 						<option value="1"<?= selected(  $event && $event->isEventAborted() ) ?>><?= __( "Sì" ) ?></option>
 					</select>
 				</div>
 			</div>
 
 			<div class="col s12">
 				<p><button type="submit" class="btn waves-effect"><?= __( "Salva" ) ?></button></p>
 			</div>
 
 		</div>
 
 		<?php foreach( Event::fields_i18n() as $i18n_column => $label ): ?>
 			<h3><?= $label ?></h3>
 			<div class="row">
 				<?php foreach( all_languages() as $lang ): ?>
 					<?php $iso = $lang->getISO() ?>
 					<?php $field = $i18n_column . '_' . $iso ?>
 					<div class="col s12 m6">
 						<div class="card-panel">
 							<label for="event-abstract"><?= $label ?> (<?= $lang->getHuman() ?>)</label>
 							<textarea name="<?= esc_attr( $field ) ?>" class="materialize-textarea"><?php
 								if( $event ) {
 									echo esc_html( $event->get( $field ) );
 								}
 							?></textarea>
 						</div>
 					</div>
 				<?php endforeach ?>
 			</div>
 		<?php endforeach ?>
 
 		<!-- Image -->
 		<div class="row">
 			<div class="col s12 m6">
 				<div class="card-panel">
 					<label for="event-image"><?= __( "Immagine" ) ?></label>
 					<input type="text" name="image"<?php
 						if( $event ) {
 							echo value( $event->get( Event::IMAGE ) );
 						}
 					?>/ >
 					<?php if( $event && $event->hasEventImage() ): ?>
 						<img src="<?= esc_attr( $event->getEventImage() ) ?>" class="responsive-img" alt="<?= esc_attr( $event->getEventTitle() ) ?>" />
 					<?php endif ?>
 				</div>
 			</div>
 		</div>
 		<!-- /Image -->
 
 		<div class="row">
 			<div class="col s12">
 				<button type="submit" class="btn waves-effect"><?= __( "Salva" ) ?></button>
 			</div>
 		</div>
 	</form>
 
 	<!-- image -->
 	<?php if( $event ): ?>
 		<form method="post" enctype="multipart/form-data">
 			<?php form_action( 'change-image' ) ?>
 			<div class="row">
 				<div class="col s12">
 					<div class="card-panel">
 
 						<h3><?= __( "Nuova Immagine" ) ?></h3>
 
 						<div class="file-field input-field">
 							<div class="btn">
 								<span><?= __( "Sfoglia" ) ?></span>
 								<input name="image" type="file" />
 							</div>
 							<div class="file-path-wrapper">
 								<input class="file-path validate" type="text" />
 							</div>
 						</div>
 						<button type="submit" class="btn waves-effect"><?= __( "Carica" ) ?></button>
 					</div>
 				</div>
 			</div>
 		</form>
 	<?php endif ?>
 	<!-- /image -->
 
 	<?php if( $event ): ?>
 	<div class="row">
 		<div class="col s12 m6">
 			<div class="card-panel">
 				<h3><?php printf(
 					__( "Associa %s" ),
 					__( "Utente" )
 				) ?></h3>
 				<form action="" method="post">
 					<?php form_action( 'add-user' ) ?>
 					<select name="user" class="browser-default">
 						<?php $users = User::factory()
 							->select( [
 								User::UID,
 								User::NAME,
 								User::SURNAME,
 							] )
 							->orderBy( User::NAME )
 							->queryGenerator();
 						?>
 						<?php foreach( $users as $user ): ?>
 							<option value="<?= $user->getUserUID() ?>">
 								<?= esc_html( $user->getUserFullname() ) ?>
 							</option>
 						<?php endforeach ?>
 					</select>
 					<p><button type="submit" class="btn"><?= __("Aggiungi") ?></button></p>
 				</form>
 
 				<p><?= HTML::a(
 					User::editURL(),
 					sprintf(
 						__( "Aggiungi %s" ),
 						sprintf(
 							__( "Nuovo %s" ),
 							__( "Utente" )
 						)
 					)
 				) ?></p>
 			</div>
 		</div>
 	</div>
 	<?php endif ?>
 
 	<?php if( $event ): ?>
 		<?php $users = $event->factoryUserByEvent()
 			->select( [
 				User::UID,
 				EventUser::ORDER,
 			] )
 			->defaultClass( EventUser::class )
 			->orderBy( EventUser::ORDER )
 			->queryGenerator();
 		?>
 
 		<?php if( $users->valid() ): ?>
 			<h3><?php printf(
 				__( "Modifica %s" ),
 				__( "Ordinamento" )
 			) ?></h3>
 			<div class="row">
 				<?php foreach( $users as $i => $user ): ?>
 					<div class="col s12 m6">
 						<div class="card-panel">
 							<div class="row">
 							<form action="" method="post">
 								<?php form_action( 'update-user' ) ?>
 								<div class="col s12 m6">
 									<input type="text" name="user"<?= value( $user->getUserUID() ) ?> />
 								</div>
 								<div class="col s12 m6">
 									<input type="number" name="order"<?= value( $user->getEventUserOrder() ) ?>" />
 								</div>
 								<div class="col s12 m6">
 									<input type="checkbox" name="delete" value="yes" id="asd-<?= $i ?>" />
 									<label for="asd-<?= $i ?>"><?= __("Elimina") ?></label>
 								</div>
 								<div class="col s12 m6">
 									<p><button type="submit" class="btn"><?= __("Salva") ?></button></p>
 									<p><small><?= HTML::a(
 										$user->getUserEditURL(),
 										sprintf(
 											__( "Modifica %s" ),
 											__( "Utente" )
 										)
 									) ?></small></p>
 								</div>
 							</form>
 							</div>
 						</div>
 					</div>
 				<?php endforeach ?>
 			</div>
 		<?php endif ?>
 	<?php endif ?>
 
+	<!-- start Sharables -->
+	<?php if( $event && $sharables ): ?>
+
+		<h3><?= __( "Materiali condivisi" ) ?></h3>
+
+		<ul class="collection">
+
+			<?php foreach( $sharables as $sharable ): ?>
+				<li class="collection-item"><?= HTML::a(
+					$sharable->getSharableEditURL(),
+					esc_html( $sharable->getSharableTitle() )
+				) ?></li>
+			<?php endforeach ?>
+
+			<!-- start add Sharable -->
+			<li><?= HTML::a(
+				Sharable::editURL( [
+					'event_ID' => $event->getEventID(),
+				]  ),
+				__( "Aggiungi" )
+			) ?></li>
+			<!-- end add Sharable -->
+
+		</ul>
+
+	<?php endif ?>
+	<!-- end Sharables -->
 <?php
 
 Footer::spawn();
diff --git a/admin/sharable.php b/admin/sharable.php
new file mode 100644
index 0000000..2d5ff01
--- /dev/null
+++ b/admin/sharable.php
@@ -0,0 +1,144 @@
+<?php
+# Suckless Conference
+# Copyright (C) 2020 Valerio Bozzolan
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+/*
+ * Event edit
+ *
+ * From this page you can create/edit an User and assign some skills/interests etc.
+ */
+
+// load configurations and framework
+require 'load.php';
+
+// editable Sharable fields
+$EDITABLE_FIELDS = [
+	Sharable::TITLE,
+	Sharable::TYPE,
+	Sharable::PATH,
+	Sharable::MIME,
+	Sharable::LICENSE,
+	Sharable::PARENT,
+];
+
+$sharable = null;
+$sharable_ID = $_GET['id'] ?? 0;
+$sharable_ID = (int) $sharable_ID;
+
+$event_ID = null;
+
+if( $sharable_ID ) {
+
+	$sharable = ( new QuerySharable() )
+		->whereSharableID( $sharable_ID )
+		->queryRow();
+
+	// no Sharable no party
+	if( !$sharable ) {
+		error( "missing sharable with ID $sharable_ID" );
+		die_with_404();
+	}
+}
+
+// check if it exists
+if( $sharable ) {
+
+	$event_ID = $sharable->getEventID();
+
+} else {
+
+	$event_ID = $_GET['event_ID'] ?? 0;
+	$event_ID = (int) $event_ID;
+
+	// no Event no party
+	if( !$event_ID ) {
+		throw new Exception( "missing Event" );
+	}
+}
+
+// check if the user submitted the form
+if( is_action( 'save-sharable' ) ) {
+
+	// data to be saved
+	$data = [];
+
+	// read and sanitize POST data
+	foreach( $EDITABLE_FIELDS as $field ) {
+
+		$v = luser_input( $_POST[ $field ] ?? '', 128 );
+		if( !$v ) {
+			$v = null;
+		}
+
+		$data[] = new DBCol( $field, $v, 'snull' );
+	}
+
+	// check if already existing
+	if( $sharable ) {
+
+		// update existing
+		( new QuerySharable() )
+			->whereSharable( $sharable )
+			->update( $data );
+	} else {
+
+		// insert a new one
+		( new QuerySharable() )
+			->insertRow( $data );
+
+		$sharable_ID = last_inserted_ID();
+	}
+
+	// POST -> redirect -> POST
+	http_redirect( Sharable::editURL( [
+		'id' => $sharable_ID,
+	] ) );
+}
+
+// print website header
+Header::spawn( null, [
+	'title' => __( "Materiale condiviso" ),
+] );
+
+?>
+
+	<form method="post">
+
+		<?php form_action( 'save-sharable' ) ?>
+
+		<?php foreach( $EDITABLE_FIELDS as $field ): ?>
+
+			<p>
+				<?= esc_html( $field ) ?><br />
+
+				<input type="text" name="<?= esc_attr( $field ) ?>"<?= value(
+					$sharable
+						? $sharable->get( $field )
+						: ( $_POST[ $field ] ?? null )
+				) ?>" />
+			</p>
+
+		<?php endforeach ?>
+
+		<button type="submit"><?= __( "Salva" ) ?></button>
+
+	</form>
+
+<?php
+
+// print website footer
+Footer::spawn();
+
diff --git a/includes/class-QuerySharable.php b/includes/class-QuerySharable.php
index 16ebb62..b608c75 100644
--- a/includes/class-QuerySharable.php
+++ b/includes/class-QuerySharable.php
@@ -1,140 +1,147 @@
 <?php
 # Suckless conference
 # Copyright (C) 2020 Valerio Bozzolan
 #
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Affero General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Affero General Public License for more details.
 #
 # You should have received a copy of the GNU Affero General Public License
 # along with this program. If not, see <http://www.gnu.org/licenses/>.
 
 // require dependent traits
 class_exists( QueryEvent::class, true );
 
 /**
  * Methods related to a QuerySharable class
  */
 trait QuerySharableTrait {
 
 	/**
 	 * Where the Sharable is...
 	 *
 	 * @param  object $event Sharable
 	 * @return self
 	 */
 	public function whereSharable( $event ) {
 		return $this->whereSharableID( $event->getSharableID() );
 	}
 
 	/**
 	 * Where the Sharable ID is...
 	 *
 	 * @param  int  $id Sharable ID
 	 * @return self
 	 */
 	public function whereSharableID( $id ) {
 		return $this->whereInt( $this->SHARABLE_ID, $id );
 	}
 
 	/**
 	 * Where the Sharable has a parent
 	 *
 	 * @param boolean $has Set to false to have not a parent
 	 * @return self
 	 */
 	public function whereSharableHasParent( $has = true ) {
 
 		// it has the parent if it's not NULL
 		$verb = $has ? 'IS NOT' : 'IS';
 		return $this->compare( Sharable::PARENT, $verb, 'NULL' );
 	}
 
 	/**
 	 * Where the Sharable has not a parent
 	 *
 	 * @param boolean $has Set to false to have not a parent
 	 * @return self
 	 */
 	public function whereSharableIsRoot() {
 		return $this->whereSharableHasParent( false );
 	}
 
 	/**
 	 * Where the Sharable has a parent and it's this one
 	 *
 	 * @param Sharable $sharable
 	 * @return self
 	 */
 	public function whereSharableParent( $sharable ) {
 		return $this->whereSharableParentID( $sharable->getSharableID() );
 	}
 
 	/**
 	 * Where the Sharable has a parent and it's this one
 	 *
 	 * @param int $id Sharable ID
 	 * @return self
 	 */
 	public function whereSharableParentID( $id ) {
 		return $this->whereInt( Sharable::PARENT, $id );
 	}
 
 	/**
 	 * Select a field called 'has_sharable_children'
 	 *
 	 * @return self
 	 */
 	public function selectSharableHasChildren( $alias = 'sharable_has_children' ) {
 
 		// check if it exists another Sharable with this row as its parent
 		$temp_subquery_alias = 'sharable_children';
 		$subquery = ( new QuerySharable( null, $temp_subquery_alias ) )
 			->equals( $temp_subquery_alias . DOT . Sharable::PARENT, Sharable::ID_ )
 			->getQuery();
 
 		return $this->select( "EXISTS( $subquery ) $alias");
 	}
 
 }
 
 /**
  * Utility used to Query a Sharable.
  */
 class QuerySharable extends Query {
 
 	use QuerySharableTrait;
 	use QueryEventTrait;
 
+	/**
+	 * Univoque Sharable ID column name
+	 *
+	 * @var
+	 */
+	protected $SHARABLE_ID = 'sharable.sharable_ID';
+
 	/**
 	 * Univoque Event ID column name
 	 *
 	 * @var
 	 */
 	protected $EVENT_ID = 'sharable.event_ID';
 
 	/**
 	 * Constructor
 	 *
 	 * @param DB     $db    Database or NULL for the default one
 	 * @param string $alias Table alias
 	 */
 	public function __construct( $db = null, $alias = true ) {
 
 		// initialize Query
 		parent::__construct();
 
 		// select default table
 		$this->fromAlias( Sharable::T, $alias );
 
 		// select default result class name
 		$this->defaultClass( Sharable::class );
 	}
 
 }
diff --git a/includes/class-Sharable.php b/includes/class-Sharable.php
index 662f43d..bec42d2 100644
--- a/includes/class-Sharable.php
+++ b/includes/class-Sharable.php
@@ -1,285 +1,313 @@
 <?php
 # Linux Day 2016 - Construct a database sharable
 # Copyright (C) 2016, 2017, 2018, 2019, 2020 Valerio Bozzolan, Linux Day Torino website contributors
 #
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Affero General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU Affero General Public License for more details.
 #
 # You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+// load dependent traits
+class_exists( Event::class, true );
+
 trait SharableTrait {
 
 	/**
 	 * Get the sharable ID
 	 *
 	 * @return int
 	 */
 	public function getSharableID() {
 		return $this->nonnull( Sharable::ID );
 	}
 
 	/**
 	 * Check if this Sharable has a parent
 	 *
 	 * See https://gitpull.it/T557
 	 *
 	 * @return boolean
 	 */
 	public function hasSharableParent() {
 		return $this->has( Sharable::PARENT );
 	}
 
 	/**
 	 * Get the ID of the parent Sharable (if any)
 	 *
 	 * See https://gitpull.it/T557
 	 *
 	 * @return mixed
 	 */
 	public function getSharableParentID() {
 		return $this->get( Sharable::PARENT );
 	}
 
 	/**
 	 * Get the localized sharable title
 	 *
 	 * @param $args array Title arguments like 'prop'
 	 * @return string
 	 */
 	public function getSharableTitle( $args = [] ) {
 		$sharable_title = $this->get( Sharable::TITLE );
 
 		if( ! isset( $sharable_title ) ) {
 			return $this->getDefaultSharableTitle( $args );
 		}
 
 		return __( $sharable_title );
 	}
 
 	/**
 	 * Retrieve something usable as a title
 	 *
 	 * @param $args array Title arguments like 'prop'
 	 * @return string
 	 */
 	public function getDefaultSharableTitle( $args = [] ) {
 
 		$sharable_type = $this->get( Sharable::TYPE );
 
 		if( $sharable_type === 'youtube' ) {
 			if( isset( $args['prop'] ) && $args['prop'] ) {
 				return sprintf( __("il %s"), __("video esterno") );
 			} else {
 				return __("video esterno");
 			}
 		}
 
 		$sharable_path = $this->get( Sharable::PATH );
 
 		// Get filename from "/asd/asd/asd/(filename)"
 		$i = 0;
 		while( strpos( $sharable_path, _, $i ) !== false ) {
 			$i++;
 		}
 		return substr( $sharable_path, $i );
 	}
 
 	/**
 	 * Is it an image?
 	 *
 	 * @return bool
 	 */
 	public function isSharableImage() {
 		return $this->isSharableType( 'image' );
 	}
 
 	/**
 	 * Is it a video?
 	 *
 	 * @return bool
 	 */
 	public function isSharableVideo() {
 		return $this->isSharableType( 'video' );
 	}
 
 	/**
 	 * Is it a document?
 	 *
 	 * @return bool
 	 */
 	public function isSharableDocument() {
 		return $this->isSharableType( 'document' );
 	}
 
 	/**
 	 * Is it an iframe (like a YouTube video?)
 	 *
 	 * @return bool
 	 */
 	public function isSharableIframe() {
 		return $this->isSharableType( 'youtube' );
 	}
 
 	/**
 	 * Is it of a certain type?
 	 *
 	 * @param $type string
 	 * @return bool
 	 */
 	private function isSharableType( $type ) {
 		return $this->get( Sharable::TYPE ) === $type;
 
 	}
 
 	/**
 	 * It can be downloaded?
 	 *
 	 * @return bool
 	 */
 	public function isSharableDownloadable() {
 		return ! $this->isSharableIframe();
 	}
 
 	/**
 	 * @TODO: $base = ROOT is wrong and should be $absolute = false
 	 */
 	function getSharablePath( $base = ROOT ) {
 		$type = $this->get( Sharable::TYPE );
 		$path = $this->get( Sharable::PATH );
 		if( 'youtube' === $type ) {
 			return "https://www.youtube.com/watch?v={$path}";
 		}
 		return site_page( $path, $base );
 	}
 
 	/**
 	 * Get the MIME type
 	 *
 	 * @return string|null
 	 */
 	public function getSharableMIME() {
 		return $this->get( Sharable::MIME );
 	}
 
 	/**
 	 * Get the license
 	 *
 	 * @return License
 	 */
 	public function getSharableLicense() {
 		return license( $this->get( Sharable::LICENSE ) );
 	}
 
+	/**
+	 * Get the Sharable edit URL
+	 *
+	 * @return self
+	 */
+	public function getSharableEditURL() {
+		return Sharable::editURL( [
+			'id' => $this->getSharableID(),
+		] );
+	}
+
 	/**
 	 * Normalize a Sharable object
 	 */
 	protected function normalizeSharable() {
 		$this->integers(
 			Sharable::ID,
 			Sharable::PARENT,
 			Event   ::ID
 		);
 	}
 }
 
 /**
  * A Sharable is an attachment related to a Talk
  */
 class Sharable extends Queried {
+
 	use SharableTrait;
+	use EventTrait;
 
 	/**
 	 * Database table name
 	 */
 	const T = 'sharable';
 
 	/**
 	 * Sharable ID column
 	 */
 	const ID = 'sharable_ID';
 
 	/**
 	 * Sharable title column
 	 */
 	const TITLE = 'sharable_title';
 
 	/**
 	 * Sharable type column
 	 */
 	const TYPE = 'sharable_type';
 
 	/**
 	 * Sharable path column
 	 */
 	const PATH = 'sharable_path';
 
 	/**
 	 * Sharable mime type column
 	 */
 	const MIME = 'sharable_mimetype';
 
 	/**
 	 * Sharable license column
 	 */
 	const LICENSE = 'sharable_license';
 
 	/**
 	 * Name of the parent sharable_ID column
 	 *
 	 * See https://gitpull.it/T557
 	 */
 	const PARENT = 'sharable_parent';
 
 	/**
 	 * Sharable univoque ID
 	 */
 	const ID_ = self::T . DOT . self::ID;
 
 	/**
 	 * Sharable event ID
 	 */
 	const EVENT_ = self::T . DOT . Event::ID;
 
 	/**
 	 * Constructor
 	 */
 	public function __construct() {
 		$this->normalizeSharable();
+		$this->normalizeEvent();
 	}
 
 	/**
 	 * Factory by an event
 	 *
 	 * @param $event_ID int Event ID
 	 * @return Query
 	 */
 	public static function factoryByEvent( $event_ID ) {
 		return ( new QuerySharable )
 			->whereEventID( $event_ID );
 	}
 
 	/**
 	 * All basic fields
 	 *
 	 * @return array
 	 */
 	public static function fields() {
 		return [
 			self::ID_,
 			self::TITLE,
 			self::TYPE,
 			self::PATH,
 			self::MIME,
 			self::LICENSE,
 			self::PARENT,
 		];
 	}
+
+	/**
+	 * Create the Sharable edit URL
+	 *
+	 * @param array $args
+	 * @return string
+	 */
+	public static function editURL( $args ) {
+		$url = site_page( ADMIN_BASE_URL . '/sharable.php' );
+		return http_build_get_query( $url, $args );
+	}
 }