Compare commits
265 Commits
#MSG01/cha
...
master
@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="android" name="Android">
|
||||
<configuration />
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/geolocator_apple/example/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/geolocator_apple/example/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/geolocator_apple/example/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/fluttertoast/example/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/fluttertoast/example/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/fluttertoast/example/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/flutter_inappwebview/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/flutter_inappwebview/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/flutter_inappwebview/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/flutter_inappwebview/example/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/flutter_inappwebview/example/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/flutter_inappwebview/example/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/flutter_native_splash/example/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/flutter_native_splash/example/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/flutter_native_splash/example/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/geolocator_apple/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/geolocator_apple/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/geolocator_apple/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/home_indicator/example/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/home_indicator/example/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/home_indicator/example/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/path_provider_ios/example/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/path_provider_ios/example/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/path_provider_ios/example/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/vibration/example/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/vibration/example/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/vibration/example/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/path_provider_ios/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/path_provider_ios/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/path_provider_ios/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/vibration/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/vibration/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/vibration/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/flutter_native_splash/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/flutter_native_splash/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/flutter_native_splash/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/fluttertoast/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/fluttertoast/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/fluttertoast/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/home_indicator/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/home_indicator/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/home_indicator/.dart_tool" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Android API 33, extension level 3 Platform" jdkType="Android SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Dart SDK" level="project" />
|
||||
<orderEntry type="library" name="Dart Packages" level="project" />
|
||||
</component>
|
||||
</module>
|
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="dataSourceStorageLocal" created-in="PS-222.4345.15">
|
||||
<data-source name="@localhost" uuid="f334e98a-3c30-4412-8c71-35fe124ed605">
|
||||
<database-info product="" version="" jdbc-version="" driver-name="" driver-version="" dbms="MARIADB" exact-version="0" />
|
||||
<secret-storage>forget</secret-storage>
|
||||
<schema-mapping />
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||
<data-source source="LOCAL" name="@localhost" uuid="f334e98a-3c30-4412-8c71-35fe124ed605">
|
||||
<driver-ref>mariadb</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.mariadb.jdbc.Driver</jdbc-driver>
|
||||
<jdbc-url>jdbc:mariadb://localhost:3306</jdbc-url>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<dataSource name="@localhost">
|
||||
<database-model serializer="dbm" dbms="MARIADB" family-id="MARIADB" format-version="4.43">
|
||||
<root id="1"/>
|
||||
<schema id="2" parent="1" name="information_schema"/>
|
||||
<schema id="3" parent="1" name="mysql"/>
|
||||
<schema id="4" parent="1" name="performance_schema"/>
|
||||
<schema id="5" parent="1" name="phpmyadmin"/>
|
||||
<schema id="6" parent="1" name="positiondaflmusic"/>
|
||||
<schema id="7" parent="1" name="projetphp"/>
|
||||
<schema id="8" parent="1" name="test"/>
|
||||
</database-model>
|
||||
</dataSource>
|
@ -0,0 +1,2 @@
|
||||
#n:information_schema
|
||||
!<md> [null, 0, null, null, -2147483648, -2147483648]
|
@ -0,0 +1,2 @@
|
||||
#n:mysql
|
||||
!<md> [null, 0, null, null, -2147483648, -2147483648]
|
@ -0,0 +1,2 @@
|
||||
#n:performance_schema
|
||||
!<md> [null, 0, null, null, -2147483648, -2147483648]
|
@ -0,0 +1,417 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DBNavigator.Project.DataEditorManager">
|
||||
<record-view-column-sorting-type value="BY_INDEX" />
|
||||
<value-preview-text-wrapping value="true" />
|
||||
<value-preview-pinned value="false" />
|
||||
</component>
|
||||
<component name="DBNavigator.Project.DatabaseFileManager">
|
||||
<open-files />
|
||||
</component>
|
||||
<component name="DBNavigator.Project.EditorStateManager">
|
||||
<last-used-providers />
|
||||
</component>
|
||||
<component name="DBNavigator.Project.Settings">
|
||||
<connections />
|
||||
<browser-settings>
|
||||
<general>
|
||||
<display-mode value="TABBED" />
|
||||
<navigation-history-size value="100" />
|
||||
<show-object-details value="false" />
|
||||
</general>
|
||||
<filters>
|
||||
<object-type-filter>
|
||||
<object-type name="SCHEMA" enabled="true" />
|
||||
<object-type name="USER" enabled="true" />
|
||||
<object-type name="ROLE" enabled="true" />
|
||||
<object-type name="PRIVILEGE" enabled="true" />
|
||||
<object-type name="CHARSET" enabled="true" />
|
||||
<object-type name="TABLE" enabled="true" />
|
||||
<object-type name="VIEW" enabled="true" />
|
||||
<object-type name="MATERIALIZED_VIEW" enabled="true" />
|
||||
<object-type name="NESTED_TABLE" enabled="true" />
|
||||
<object-type name="COLUMN" enabled="true" />
|
||||
<object-type name="INDEX" enabled="true" />
|
||||
<object-type name="CONSTRAINT" enabled="true" />
|
||||
<object-type name="DATASET_TRIGGER" enabled="true" />
|
||||
<object-type name="DATABASE_TRIGGER" enabled="true" />
|
||||
<object-type name="SYNONYM" enabled="true" />
|
||||
<object-type name="SEQUENCE" enabled="true" />
|
||||
<object-type name="PROCEDURE" enabled="true" />
|
||||
<object-type name="FUNCTION" enabled="true" />
|
||||
<object-type name="PACKAGE" enabled="true" />
|
||||
<object-type name="TYPE" enabled="true" />
|
||||
<object-type name="TYPE_ATTRIBUTE" enabled="true" />
|
||||
<object-type name="ARGUMENT" enabled="true" />
|
||||
<object-type name="DIMENSION" enabled="true" />
|
||||
<object-type name="CLUSTER" enabled="true" />
|
||||
<object-type name="DBLINK" enabled="true" />
|
||||
</object-type-filter>
|
||||
</filters>
|
||||
<sorting>
|
||||
<object-type name="COLUMN" sorting-type="NAME" />
|
||||
<object-type name="FUNCTION" sorting-type="NAME" />
|
||||
<object-type name="PROCEDURE" sorting-type="NAME" />
|
||||
<object-type name="ARGUMENT" sorting-type="POSITION" />
|
||||
<object-type name="TYPE ATTRIBUTE" sorting-type="POSITION" />
|
||||
</sorting>
|
||||
<default-editors>
|
||||
<object-type name="VIEW" editor-type="SELECTION" />
|
||||
<object-type name="PACKAGE" editor-type="SELECTION" />
|
||||
<object-type name="TYPE" editor-type="SELECTION" />
|
||||
</default-editors>
|
||||
</browser-settings>
|
||||
<navigation-settings>
|
||||
<lookup-filters>
|
||||
<lookup-objects>
|
||||
<object-type name="SCHEMA" enabled="true" />
|
||||
<object-type name="USER" enabled="false" />
|
||||
<object-type name="ROLE" enabled="false" />
|
||||
<object-type name="PRIVILEGE" enabled="false" />
|
||||
<object-type name="CHARSET" enabled="false" />
|
||||
<object-type name="TABLE" enabled="true" />
|
||||
<object-type name="VIEW" enabled="true" />
|
||||
<object-type name="MATERIALIZED VIEW" enabled="true" />
|
||||
<object-type name="INDEX" enabled="true" />
|
||||
<object-type name="CONSTRAINT" enabled="true" />
|
||||
<object-type name="DATASET TRIGGER" enabled="true" />
|
||||
<object-type name="DATABASE TRIGGER" enabled="true" />
|
||||
<object-type name="SYNONYM" enabled="false" />
|
||||
<object-type name="SEQUENCE" enabled="true" />
|
||||
<object-type name="PROCEDURE" enabled="true" />
|
||||
<object-type name="FUNCTION" enabled="true" />
|
||||
<object-type name="PACKAGE" enabled="true" />
|
||||
<object-type name="TYPE" enabled="true" />
|
||||
<object-type name="DIMENSION" enabled="false" />
|
||||
<object-type name="CLUSTER" enabled="false" />
|
||||
<object-type name="DBLINK" enabled="true" />
|
||||
</lookup-objects>
|
||||
<force-database-load value="false" />
|
||||
<prompt-connection-selection value="true" />
|
||||
<prompt-schema-selection value="true" />
|
||||
</lookup-filters>
|
||||
</navigation-settings>
|
||||
<dataset-grid-settings>
|
||||
<general>
|
||||
<enable-zooming value="true" />
|
||||
<enable-column-tooltip value="true" />
|
||||
</general>
|
||||
<sorting>
|
||||
<nulls-first value="true" />
|
||||
<max-sorting-columns value="4" />
|
||||
</sorting>
|
||||
<audit-columns>
|
||||
<column-names value="" />
|
||||
<visible value="true" />
|
||||
<editable value="false" />
|
||||
</audit-columns>
|
||||
</dataset-grid-settings>
|
||||
<dataset-editor-settings>
|
||||
<text-editor-popup>
|
||||
<active value="false" />
|
||||
<active-if-empty value="false" />
|
||||
<data-length-threshold value="100" />
|
||||
<popup-delay value="1000" />
|
||||
</text-editor-popup>
|
||||
<values-actions-popup>
|
||||
<show-popup-button value="true" />
|
||||
<element-count-threshold value="1000" />
|
||||
<data-length-threshold value="250" />
|
||||
</values-actions-popup>
|
||||
<general>
|
||||
<fetch-block-size value="100" />
|
||||
<fetch-timeout value="30" />
|
||||
<trim-whitespaces value="true" />
|
||||
<convert-empty-strings-to-null value="true" />
|
||||
<select-content-on-cell-edit value="true" />
|
||||
<large-value-preview-active value="true" />
|
||||
</general>
|
||||
<filters>
|
||||
<prompt-filter-dialog value="true" />
|
||||
<default-filter-type value="BASIC" />
|
||||
</filters>
|
||||
<qualified-text-editor text-length-threshold="300">
|
||||
<content-types>
|
||||
<content-type name="Text" enabled="true" />
|
||||
<content-type name="Properties" enabled="true" />
|
||||
<content-type name="XML" enabled="true" />
|
||||
<content-type name="DTD" enabled="true" />
|
||||
<content-type name="HTML" enabled="true" />
|
||||
<content-type name="XHTML" enabled="true" />
|
||||
<content-type name="Java" enabled="true" />
|
||||
<content-type name="SQL" enabled="true" />
|
||||
<content-type name="PL/SQL" enabled="true" />
|
||||
<content-type name="JSON" enabled="true" />
|
||||
<content-type name="JSON5" enabled="true" />
|
||||
<content-type name="Groovy" enabled="true" />
|
||||
<content-type name="AIDL" enabled="true" />
|
||||
<content-type name="YAML" enabled="true" />
|
||||
<content-type name="Manifest" enabled="true" />
|
||||
</content-types>
|
||||
</qualified-text-editor>
|
||||
<record-navigation>
|
||||
<navigation-target value="VIEWER" />
|
||||
</record-navigation>
|
||||
</dataset-editor-settings>
|
||||
<code-editor-settings>
|
||||
<general>
|
||||
<show-object-navigation-gutter value="false" />
|
||||
<show-spec-declaration-navigation-gutter value="true" />
|
||||
<enable-spellchecking value="true" />
|
||||
<enable-reference-spellchecking value="false" />
|
||||
</general>
|
||||
<confirmations>
|
||||
<save-changes value="false" />
|
||||
<revert-changes value="true" />
|
||||
</confirmations>
|
||||
</code-editor-settings>
|
||||
<code-completion-settings>
|
||||
<filters>
|
||||
<basic-filter>
|
||||
<filter-element type="RESERVED_WORD" id="keyword" selected="true" />
|
||||
<filter-element type="RESERVED_WORD" id="function" selected="true" />
|
||||
<filter-element type="RESERVED_WORD" id="parameter" selected="true" />
|
||||
<filter-element type="RESERVED_WORD" id="datatype" selected="true" />
|
||||
<filter-element type="RESERVED_WORD" id="exception" selected="true" />
|
||||
<filter-element type="OBJECT" id="schema" selected="true" />
|
||||
<filter-element type="OBJECT" id="role" selected="true" />
|
||||
<filter-element type="OBJECT" id="user" selected="true" />
|
||||
<filter-element type="OBJECT" id="privilege" selected="true" />
|
||||
<user-schema>
|
||||
<filter-element type="OBJECT" id="table" selected="true" />
|
||||
<filter-element type="OBJECT" id="view" selected="true" />
|
||||
<filter-element type="OBJECT" id="materialized view" selected="true" />
|
||||
<filter-element type="OBJECT" id="index" selected="true" />
|
||||
<filter-element type="OBJECT" id="constraint" selected="true" />
|
||||
<filter-element type="OBJECT" id="trigger" selected="true" />
|
||||
<filter-element type="OBJECT" id="synonym" selected="false" />
|
||||
<filter-element type="OBJECT" id="sequence" selected="true" />
|
||||
<filter-element type="OBJECT" id="procedure" selected="true" />
|
||||
<filter-element type="OBJECT" id="function" selected="true" />
|
||||
<filter-element type="OBJECT" id="package" selected="true" />
|
||||
<filter-element type="OBJECT" id="type" selected="true" />
|
||||
<filter-element type="OBJECT" id="dimension" selected="true" />
|
||||
<filter-element type="OBJECT" id="cluster" selected="true" />
|
||||
<filter-element type="OBJECT" id="dblink" selected="true" />
|
||||
</user-schema>
|
||||
<public-schema>
|
||||
<filter-element type="OBJECT" id="table" selected="false" />
|
||||
<filter-element type="OBJECT" id="view" selected="false" />
|
||||
<filter-element type="OBJECT" id="materialized view" selected="false" />
|
||||
<filter-element type="OBJECT" id="index" selected="false" />
|
||||
<filter-element type="OBJECT" id="constraint" selected="false" />
|
||||
<filter-element type="OBJECT" id="trigger" selected="false" />
|
||||
<filter-element type="OBJECT" id="synonym" selected="false" />
|
||||
<filter-element type="OBJECT" id="sequence" selected="false" />
|
||||
<filter-element type="OBJECT" id="procedure" selected="false" />
|
||||
<filter-element type="OBJECT" id="function" selected="false" />
|
||||
<filter-element type="OBJECT" id="package" selected="false" />
|
||||
<filter-element type="OBJECT" id="type" selected="false" />
|
||||
<filter-element type="OBJECT" id="dimension" selected="false" />
|
||||
<filter-element type="OBJECT" id="cluster" selected="false" />
|
||||
<filter-element type="OBJECT" id="dblink" selected="false" />
|
||||
</public-schema>
|
||||
<any-schema>
|
||||
<filter-element type="OBJECT" id="table" selected="true" />
|
||||
<filter-element type="OBJECT" id="view" selected="true" />
|
||||
<filter-element type="OBJECT" id="materialized view" selected="true" />
|
||||
<filter-element type="OBJECT" id="index" selected="true" />
|
||||
<filter-element type="OBJECT" id="constraint" selected="true" />
|
||||
<filter-element type="OBJECT" id="trigger" selected="true" />
|
||||
<filter-element type="OBJECT" id="synonym" selected="true" />
|
||||
<filter-element type="OBJECT" id="sequence" selected="true" />
|
||||
<filter-element type="OBJECT" id="procedure" selected="true" />
|
||||
<filter-element type="OBJECT" id="function" selected="true" />
|
||||
<filter-element type="OBJECT" id="package" selected="true" />
|
||||
<filter-element type="OBJECT" id="type" selected="true" />
|
||||
<filter-element type="OBJECT" id="dimension" selected="true" />
|
||||
<filter-element type="OBJECT" id="cluster" selected="true" />
|
||||
<filter-element type="OBJECT" id="dblink" selected="true" />
|
||||
</any-schema>
|
||||
</basic-filter>
|
||||
<extended-filter>
|
||||
<filter-element type="RESERVED_WORD" id="keyword" selected="true" />
|
||||
<filter-element type="RESERVED_WORD" id="function" selected="true" />
|
||||
<filter-element type="RESERVED_WORD" id="parameter" selected="true" />
|
||||
<filter-element type="RESERVED_WORD" id="datatype" selected="true" />
|
||||
<filter-element type="RESERVED_WORD" id="exception" selected="true" />
|
||||
<filter-element type="OBJECT" id="schema" selected="true" />
|
||||
<filter-element type="OBJECT" id="user" selected="true" />
|
||||
<filter-element type="OBJECT" id="role" selected="true" />
|
||||
<filter-element type="OBJECT" id="privilege" selected="true" />
|
||||
<user-schema>
|
||||
<filter-element type="OBJECT" id="table" selected="true" />
|
||||
<filter-element type="OBJECT" id="view" selected="true" />
|
||||
<filter-element type="OBJECT" id="materialized view" selected="true" />
|
||||
<filter-element type="OBJECT" id="index" selected="true" />
|
||||
<filter-element type="OBJECT" id="constraint" selected="true" />
|
||||
<filter-element type="OBJECT" id="trigger" selected="true" />
|
||||
<filter-element type="OBJECT" id="synonym" selected="true" />
|
||||
<filter-element type="OBJECT" id="sequence" selected="true" />
|
||||
<filter-element type="OBJECT" id="procedure" selected="true" />
|
||||
<filter-element type="OBJECT" id="function" selected="true" />
|
||||
<filter-element type="OBJECT" id="package" selected="true" />
|
||||
<filter-element type="OBJECT" id="type" selected="true" />
|
||||
<filter-element type="OBJECT" id="dimension" selected="true" />
|
||||
<filter-element type="OBJECT" id="cluster" selected="true" />
|
||||
<filter-element type="OBJECT" id="dblink" selected="true" />
|
||||
</user-schema>
|
||||
<public-schema>
|
||||
<filter-element type="OBJECT" id="table" selected="true" />
|
||||
<filter-element type="OBJECT" id="view" selected="true" />
|
||||
<filter-element type="OBJECT" id="materialized view" selected="true" />
|
||||
<filter-element type="OBJECT" id="index" selected="true" />
|
||||
<filter-element type="OBJECT" id="constraint" selected="true" />
|
||||
<filter-element type="OBJECT" id="trigger" selected="true" />
|
||||
<filter-element type="OBJECT" id="synonym" selected="true" />
|
||||
<filter-element type="OBJECT" id="sequence" selected="true" />
|
||||
<filter-element type="OBJECT" id="procedure" selected="true" />
|
||||
<filter-element type="OBJECT" id="function" selected="true" />
|
||||
<filter-element type="OBJECT" id="package" selected="true" />
|
||||
<filter-element type="OBJECT" id="type" selected="true" />
|
||||
<filter-element type="OBJECT" id="dimension" selected="true" />
|
||||
<filter-element type="OBJECT" id="cluster" selected="true" />
|
||||
<filter-element type="OBJECT" id="dblink" selected="true" />
|
||||
</public-schema>
|
||||
<any-schema>
|
||||
<filter-element type="OBJECT" id="table" selected="true" />
|
||||
<filter-element type="OBJECT" id="view" selected="true" />
|
||||
<filter-element type="OBJECT" id="materialized view" selected="true" />
|
||||
<filter-element type="OBJECT" id="index" selected="true" />
|
||||
<filter-element type="OBJECT" id="constraint" selected="true" />
|
||||
<filter-element type="OBJECT" id="trigger" selected="true" />
|
||||
<filter-element type="OBJECT" id="synonym" selected="true" />
|
||||
<filter-element type="OBJECT" id="sequence" selected="true" />
|
||||
<filter-element type="OBJECT" id="procedure" selected="true" />
|
||||
<filter-element type="OBJECT" id="function" selected="true" />
|
||||
<filter-element type="OBJECT" id="package" selected="true" />
|
||||
<filter-element type="OBJECT" id="type" selected="true" />
|
||||
<filter-element type="OBJECT" id="dimension" selected="true" />
|
||||
<filter-element type="OBJECT" id="cluster" selected="true" />
|
||||
<filter-element type="OBJECT" id="dblink" selected="true" />
|
||||
</any-schema>
|
||||
</extended-filter>
|
||||
</filters>
|
||||
<sorting enabled="true">
|
||||
<sorting-element type="RESERVED_WORD" id="keyword" />
|
||||
<sorting-element type="RESERVED_WORD" id="datatype" />
|
||||
<sorting-element type="OBJECT" id="column" />
|
||||
<sorting-element type="OBJECT" id="table" />
|
||||
<sorting-element type="OBJECT" id="view" />
|
||||
<sorting-element type="OBJECT" id="materialized view" />
|
||||
<sorting-element type="OBJECT" id="index" />
|
||||
<sorting-element type="OBJECT" id="constraint" />
|
||||
<sorting-element type="OBJECT" id="trigger" />
|
||||
<sorting-element type="OBJECT" id="synonym" />
|
||||
<sorting-element type="OBJECT" id="sequence" />
|
||||
<sorting-element type="OBJECT" id="procedure" />
|
||||
<sorting-element type="OBJECT" id="function" />
|
||||
<sorting-element type="OBJECT" id="package" />
|
||||
<sorting-element type="OBJECT" id="type" />
|
||||
<sorting-element type="OBJECT" id="dimension" />
|
||||
<sorting-element type="OBJECT" id="cluster" />
|
||||
<sorting-element type="OBJECT" id="dblink" />
|
||||
<sorting-element type="OBJECT" id="schema" />
|
||||
<sorting-element type="OBJECT" id="role" />
|
||||
<sorting-element type="OBJECT" id="user" />
|
||||
<sorting-element type="RESERVED_WORD" id="function" />
|
||||
<sorting-element type="RESERVED_WORD" id="parameter" />
|
||||
</sorting>
|
||||
<format>
|
||||
<enforce-code-style-case value="true" />
|
||||
</format>
|
||||
</code-completion-settings>
|
||||
<execution-engine-settings>
|
||||
<statement-execution>
|
||||
<fetch-block-size value="100" />
|
||||
<execution-timeout value="20" />
|
||||
<debug-execution-timeout value="600" />
|
||||
<focus-result value="false" />
|
||||
<prompt-execution value="false" />
|
||||
</statement-execution>
|
||||
<script-execution>
|
||||
<command-line-interfaces />
|
||||
<execution-timeout value="300" />
|
||||
</script-execution>
|
||||
<method-execution>
|
||||
<execution-timeout value="30" />
|
||||
<debug-execution-timeout value="600" />
|
||||
<parameter-history-size value="10" />
|
||||
</method-execution>
|
||||
</execution-engine-settings>
|
||||
<operation-settings>
|
||||
<transactions>
|
||||
<uncommitted-changes>
|
||||
<on-project-close value="ASK" />
|
||||
<on-disconnect value="ASK" />
|
||||
<on-autocommit-toggle value="ASK" />
|
||||
</uncommitted-changes>
|
||||
<multiple-uncommitted-changes>
|
||||
<on-commit value="ASK" />
|
||||
<on-rollback value="ASK" />
|
||||
</multiple-uncommitted-changes>
|
||||
</transactions>
|
||||
<session-browser>
|
||||
<disconnect-session value="ASK" />
|
||||
<kill-session value="ASK" />
|
||||
<reload-on-filter-change value="false" />
|
||||
</session-browser>
|
||||
<compiler>
|
||||
<compile-type value="KEEP" />
|
||||
<compile-dependencies value="ASK" />
|
||||
<always-show-controls value="false" />
|
||||
</compiler>
|
||||
<debugger>
|
||||
<debugger-type value="ASK" />
|
||||
<use-generic-runners value="true" />
|
||||
</debugger>
|
||||
</operation-settings>
|
||||
<ddl-file-settings>
|
||||
<extensions>
|
||||
<mapping file-type-id="VIEW" extensions="vw" />
|
||||
<mapping file-type-id="TRIGGER" extensions="trg" />
|
||||
<mapping file-type-id="PROCEDURE" extensions="prc" />
|
||||
<mapping file-type-id="FUNCTION" extensions="fnc" />
|
||||
<mapping file-type-id="PACKAGE" extensions="pkg" />
|
||||
<mapping file-type-id="PACKAGE_SPEC" extensions="pks" />
|
||||
<mapping file-type-id="PACKAGE_BODY" extensions="pkb" />
|
||||
<mapping file-type-id="TYPE" extensions="tpe" />
|
||||
<mapping file-type-id="TYPE_SPEC" extensions="tps" />
|
||||
<mapping file-type-id="TYPE_BODY" extensions="tpb" />
|
||||
</extensions>
|
||||
<general>
|
||||
<lookup-ddl-files value="true" />
|
||||
<create-ddl-files value="false" />
|
||||
<synchronize-ddl-files value="true" />
|
||||
<use-qualified-names value="false" />
|
||||
<make-scripts-rerunnable value="true" />
|
||||
</general>
|
||||
</ddl-file-settings>
|
||||
<general-settings>
|
||||
<regional-settings>
|
||||
<date-format value="MEDIUM" />
|
||||
<number-format value="UNGROUPED" />
|
||||
<locale value="SYSTEM_DEFAULT" />
|
||||
<use-custom-formats value="false" />
|
||||
</regional-settings>
|
||||
<environment>
|
||||
<environment-types>
|
||||
<environment-type id="development" name="Development" description="Development environment" color="-2430209/-12296320" readonly-code="false" readonly-data="false" />
|
||||
<environment-type id="integration" name="Integration" description="Integration environment" color="-2621494/-12163514" readonly-code="true" readonly-data="false" />
|
||||
<environment-type id="production" name="Production" description="Productive environment" color="-11574/-10271420" readonly-code="true" readonly-data="true" />
|
||||
<environment-type id="other" name="Other" description="" color="-1576/-10724543" readonly-code="false" readonly-data="false" />
|
||||
</environment-types>
|
||||
<visibility-settings>
|
||||
<connection-tabs value="true" />
|
||||
<dialog-headers value="true" />
|
||||
<object-editor-tabs value="true" />
|
||||
<script-editor-tabs value="false" />
|
||||
<execution-result-tabs value="true" />
|
||||
</visibility-settings>
|
||||
</environment>
|
||||
</general-settings>
|
||||
</component>
|
||||
<component name="DBNavigator.Project.StatementExecutionManager">
|
||||
<execution-variables />
|
||||
</component>
|
||||
</project>
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="8.1">
|
||||
<option name="suggestChangeDefaultLanguageLevel" value="false" />
|
||||
</component>
|
||||
</project>
|
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="SqlDialectMappings">
|
||||
<file url="file://$PROJECT_DIR$/Sources/php_script/script/insertAndMakeListUser.php" dialect="GenericSQL" />
|
||||
<file url="file://$PROJECT_DIR$/Sources/php_script/script/test.php" dialect="GenericSQL" />
|
||||
</component>
|
||||
</project>
|
After Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 135 KiB |
@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/spec" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/symfony/translation" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/nesbot/carbon" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/pimple/pimple" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/psr/simple-cache" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/psr/http-message" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/illuminate/support" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/psr/container" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/doctrine/inflector" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/illuminate/contracts" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/slim/slim" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/illuminate/database" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/illuminate/container" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/nikic/fast-route" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/composer" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/symfony/polyfill-php80" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/kylekatarnls/update-helper" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/symfony/translation-contracts" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/symfony/polyfill-mbstring" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/api_database.iml" filepath="$PROJECT_DIR$/.idea/api_database.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PhpIncludePathManager">
|
||||
<include_path>
|
||||
<path value="$PROJECT_DIR$/sources/vendor/symfony/translation" />
|
||||
<path value="$PROJECT_DIR$/sources/vendor/nesbot/carbon" />
|
||||
<path value="$PROJECT_DIR$/sources/vendor/pimple/pimple" />
|
||||
<path value="$PROJECT_DIR$/sources/vendor/psr/simple-cache" />
|
||||
<path value="$PROJECT_DIR$/sources/vendor/psr/http-message" />
|
||||
<path value="$PROJECT_DIR$/sources/vendor/illuminate/support" />
|
||||
<path value="$PROJECT_DIR$/sources/vendor/psr/container" />
|
||||
<path value="$PROJECT_DIR$/sources/vendor/doctrine/inflector" />
|
||||
<path value="$PROJECT_DIR$/sources/vendor/illuminate/contracts" />
|
||||
<path value="$PROJECT_DIR$/sources/vendor/slim/slim" />
|
||||
<path value="$PROJECT_DIR$/sources/vendor/illuminate/database" />
|
||||
<path value="$PROJECT_DIR$/sources/vendor/illuminate/container" />
|
||||
<path value="$PROJECT_DIR$/sources/vendor/nikic/fast-route" />
|
||||
<path value="$PROJECT_DIR$/sources/vendor/composer" />
|
||||
<path value="$PROJECT_DIR$/sources/vendor/symfony/polyfill-php80" />
|
||||
<path value="$PROJECT_DIR$/sources/vendor/kylekatarnls/update-helper" />
|
||||
<path value="$PROJECT_DIR$/sources/vendor/symfony/translation-contracts" />
|
||||
<path value="$PROJECT_DIR$/sources/vendor/symfony/polyfill-mbstring" />
|
||||
</include_path>
|
||||
</component>
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="7.4">
|
||||
<option name="suggestChangeDefaultLanguageLevel" value="false" />
|
||||
</component>
|
||||
</project>
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="SqlDialectMappings">
|
||||
<file url="file://$PROJECT_DIR$/database/dafl_music.sql" dialect="MariaDB" />
|
||||
</component>
|
||||
</project>
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
@ -0,0 +1,61 @@
|
||||
-- phpMyAdmin SQL Dump
|
||||
-- version 5.2.0
|
||||
-- https://www.phpmyadmin.net/
|
||||
--
|
||||
-- Host: localhost
|
||||
-- Generation Time: Dec 25, 2022 at 09:09 PM
|
||||
-- Server version: 10.9.4-MariaDB
|
||||
-- PHP Version: 8.1.13
|
||||
|
||||
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
|
||||
START TRANSACTION;
|
||||
SET time_zone = "+00:00";
|
||||
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT = @@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS = @@CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION = @@COLLATION_CONNECTION */;
|
||||
/*!40101 SET NAMES utf8mb4 */;
|
||||
|
||||
--
|
||||
-- Database: `dafl_music`
|
||||
--
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `users`
|
||||
--
|
||||
|
||||
CREATE TABLE `users`
|
||||
(
|
||||
`idDafl` varchar(25) NOT NULL,
|
||||
`idSpotify` varchar(25) NOT NULL,
|
||||
`password` varchar(250) NOT NULL
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4
|
||||
COLLATE = utf8mb4_unicode_ci;
|
||||
|
||||
--
|
||||
-- Dumping data for table `users`
|
||||
--
|
||||
|
||||
INSERT INTO `users` (`idDafl`, `idSpotify`, `password`)
|
||||
VALUES ('felix', 'idspotfelix', 'mdp'),
|
||||
('lucas', 'spottest', 'pwdtest');
|
||||
|
||||
--
|
||||
-- Indexes for dumped tables
|
||||
--
|
||||
|
||||
--
|
||||
-- Indexes for table `users`
|
||||
--
|
||||
ALTER TABLE `users`
|
||||
ADD PRIMARY KEY (`idDafl`),
|
||||
ADD UNIQUE KEY `idSpotify` (`idSpotify`);
|
||||
COMMIT;
|
||||
|
||||
/*!40101 SET CHARACTER_SET_CLIENT = @OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS = @OLD_CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET COLLATION_CONNECTION = @OLD_COLLATION_CONNECTION */;
|
@ -0,0 +1 @@
|
||||
vendor/*
|
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
class Connection extends PDO
|
||||
{
|
||||
|
||||
private $stmt;
|
||||
|
||||
public function __construct(string $dsn, string $username, string $password)
|
||||
{
|
||||
|
||||
parent::__construct($dsn, $username, $password);
|
||||
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
}
|
||||
|
||||
|
||||
/** * @param string $query
|
||||
* @param array $parameters *
|
||||
* @return bool Returns `true` on success, `false` otherwise
|
||||
*/
|
||||
public function executeQuery(string $query, array $parameters = []): bool
|
||||
{
|
||||
$this->stmt = parent::prepare($query);
|
||||
foreach ($parameters as $name => $value) {
|
||||
$this->stmt->bindValue($name, $value[0], $value[1]);
|
||||
}
|
||||
|
||||
return $this->stmt->execute();
|
||||
}
|
||||
|
||||
public function getResults(): array
|
||||
{
|
||||
return $this->stmt->fetchall();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
require "gateways/UserGateway.php";
|
||||
require "gateways/LikesGateway.php";
|
||||
require "business/User.php";
|
||||
|
||||
class Model
|
||||
{
|
||||
public function getInformationsUser($id): array
|
||||
{
|
||||
global $app;
|
||||
$db = $app->getContainer()['settings']['db'];
|
||||
$id = filter_var($id, FILTER_SANITIZE_STRING);
|
||||
$gw = new UserGateway(new Connection($db['dsn'], $db['user'], $db['pass']));
|
||||
$userDb = $gw->getInformations($id);
|
||||
if (count($userDb) != 1) {
|
||||
throw new Exception("no user matches id");
|
||||
}
|
||||
$user = new User($userDb[0][0], $userDb[0][1]);
|
||||
return $user->getInformations();
|
||||
}
|
||||
|
||||
public function addUser($idDafl, $idSpotify, $passw): void
|
||||
{
|
||||
global $app;
|
||||
$db = $app->getContainer()['settings']['db'];
|
||||
|
||||
$data = [];
|
||||
$data['idDafl'] = filter_var($idDafl, FILTER_SANITIZE_STRING);
|
||||
$data['idSpotify'] = filter_var($idSpotify, FILTER_SANITIZE_STRING);
|
||||
$data['passw'] = filter_var($passw, FILTER_SANITIZE_STRING);
|
||||
$gw = new UserGateway(new Connection($db['dsn'], $db['user'], $db['pass']));
|
||||
$gw->addUser($data['idDafl'], $data['idSpotify'], $data['passw']);
|
||||
}
|
||||
|
||||
public function like($user,$liked) : bool {
|
||||
global $app;
|
||||
$db = $app->getContainer()['settings']['db'];
|
||||
|
||||
$data = [];
|
||||
$data['user'] = filter_var($user, FILTER_SANITIZE_STRING);
|
||||
$data['liked'] = filter_var($liked, FILTER_SANITIZE_STRING);
|
||||
$gw = new LikesGateway(new Connection($db['dsn'], $db['user'], $db['pass']));
|
||||
return $gw->addUser($data['idDafl'], $data['idSpotify'], $data['passw']);
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
class User
|
||||
{
|
||||
private string $idDafl;
|
||||
private string $idSpotify;
|
||||
|
||||
public function __construct(string $idDafl, string $idSpotify)
|
||||
{
|
||||
$this->idDafl = $idDafl;
|
||||
$this->idSpotify = $idSpotify;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getIdDafl(): string
|
||||
{
|
||||
return $this->idDafl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getIdSpotify(): string
|
||||
{
|
||||
return $this->idSpotify;
|
||||
}
|
||||
|
||||
public function getInformations(): array
|
||||
{
|
||||
return array($this->idDafl, $this->idSpotify);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
$config['displayErrorDetails'] = true;
|
||||
$config['addContentLengthHeader'] = false;
|
||||
|
||||
$config['db']['dsn'] = 'mysql:host=localhost;dbname=dafl_music';
|
||||
$config['db']['user'] = 'root';
|
||||
$config['db']['pass'] = 'root';
|
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
class LikesGateway
|
||||
{
|
||||
private Connection $con;
|
||||
|
||||
public function __construct(Connection $con)
|
||||
{
|
||||
$this->con = $con;
|
||||
}
|
||||
|
||||
public function addLike($user,$liked):bool
|
||||
{
|
||||
$query = 'INSERT INTO likes VALUES (:user,:liked)';
|
||||
$this->con->executeQuery($query,array(':user'=>array($user,PDO::PARAM_STR),':liked'=>array($liked,PDO::PARAM_STR)));
|
||||
$query = 'SELECT * FROM likes WHERE (user=:user AND liked=:liked) OR (liked=:liked AND user=:user )';
|
||||
$this->con->executeQuery($query,array(':user'=>array($user,PDO::PARAM_STR),':liked'=>array($liked,PDO::PARAM_STR)));
|
||||
$res=$this->con->getResults();
|
||||
if(count($res) == 2) {
|
||||
$query = 'INSERT INTO matches VALUES (:user,:liked)';
|
||||
$this->con->executeQuery($query,array(':user'=>array($user,PDO::PARAM_STR),':liked'=>array($liked,PDO::PARAM_STR)));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
class UserGateway
|
||||
{
|
||||
private Connection $con;
|
||||
|
||||
public function __construct(Connection $con)
|
||||
{
|
||||
$this->con = $con;
|
||||
}
|
||||
|
||||
public function getInformations($id): array
|
||||
{
|
||||
$query = 'SELECT idDafl,idSpotify FROM users WHERE idDafl=:id';
|
||||
$this->con->executeQuery($query, array(':id' => array($id, PDO::PARAM_STR)));
|
||||
return $this->con->getResults();
|
||||
}
|
||||
|
||||
public function addUser($idDafl, $idSpotify, $passw)
|
||||
{
|
||||
$query = 'INSERT INTO users VALUES (:idDafl,:idSpotify,:passw)';
|
||||
$this->con->executeQuery($query, array(':idDafl' => array($idDafl, PDO::PARAM_STR), ':idSpotify' => array($idSpotify, PDO::PARAM_STR), ':passw' => array($passw, PDO::PARAM_STR)));
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
use \Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use \Psr\Http\Message\ResponseInterface as Response;
|
||||
|
||||
require "Model.php";
|
||||
require "Connection.php";
|
||||
|
||||
// Get information about a user
|
||||
$app->get('/users/{id}', function (Request $request, Response $response, array $args) {
|
||||
try {
|
||||
$mdl = new Model();
|
||||
$res = $mdl->getInformationsUser($args['id']);
|
||||
} catch (Exception $e) {
|
||||
$res = array("Error: " . $e->getMessage());
|
||||
} finally {
|
||||
$response->getBody()->write(json_encode($res));
|
||||
return $response;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Add a user
|
||||
$app->post('/users/new', function (Request $request, Response $response, array $args) {
|
||||
try {
|
||||
$mdl = new Model();
|
||||
$data = $request->getParsedBody();
|
||||
if (!isset($data['idDafl']) || !isset($data['idSpotify']) || !isset($data['passw'])) {
|
||||
throw new Exception("missing arguments");
|
||||
}
|
||||
$mdl->addUser($data['idDafl'], $data['idSpotify'], $data['passw']);
|
||||
$res = "Ok";
|
||||
} catch (Exception $e) {
|
||||
$res = array("Error: " . $e->getMessage());
|
||||
} finally {
|
||||
$response->getBody()->write(json_encode($res));
|
||||
return $response;
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
// Update information about a user
|
||||
$app->put('/users/{id}', function (Request $request, Response $response, array $args) {
|
||||
$res = "Update infos of user " . $args['id'];
|
||||
$response->getBody()->write($res);
|
||||
|
||||
return $response;
|
||||
});
|
||||
|
||||
// Delete a user
|
||||
$app->delete('/users/{id}', function (Request $request, Response $response, array $args) {
|
||||
$res = "Delete user " . $args['id'];
|
||||
$response->getBody()->write($res);
|
||||
|
||||
return $response;
|
||||
});
|
||||
*/
|
||||
// Like someone
|
||||
$app->post('/user/{id}/like', function (Request $request, Response $response, array $args) {
|
||||
try {
|
||||
$mdl = new Model();
|
||||
$data = $request->getParsedBody();
|
||||
if (!isset($data['liked'])) {
|
||||
throw new Exception("missing arguments");
|
||||
}
|
||||
$res=($mdl->like($args["id"],$data["liked"])) ? "Match" : "Ok";
|
||||
} catch (Exception $e) {
|
||||
$res = array("Error: " . $e->getMessage());
|
||||
} finally {
|
||||
$response->getBody()->write(json_encode($res));
|
||||
return $response;
|
||||
}
|
||||
});
|
||||
/*
|
||||
// Add a new song as a preference for a situation
|
||||
$app->post('/users/{id}/preferences', function (Request $request, Response $response, array $args) {
|
||||
$res = "User " . $args['id'] . " add music " . $args['music'] . " to his preferences for category " . $args['categ'];
|
||||
$response->getBody()->write($res);
|
||||
|
||||
return $response;
|
||||
});
|
||||
*/
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"require": {
|
||||
"slim/slim": "3.*",
|
||||
"illuminate/database": "~5.1",
|
||||
"ext-json": "*"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"kylekatarnls/update-helper": true
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
// Files auto-loading
|
||||
require '../vendor/autoload.php';
|
||||
|
||||
// Configuration
|
||||
require '../app/config.php';
|
||||
|
||||
// App instantiation
|
||||
$app = new \Slim\App(['settings' => $config]);
|
||||
|
||||
// Routes
|
||||
require '../app/routes.php';
|
||||
|
||||
// Run
|
||||
$app->run();
|
@ -1,2 +1,2 @@
|
||||
FROM httpd:2.4
|
||||
COPY ./public-html/ /usr/local/apache2/htdocs/
|
||||
COPY ./sources/ /usr/local/apache2/htdocs/
|
@ -1 +0,0 @@
|
||||
Hello world Dafl !
|
@ -1,300 +0,0 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:math';
|
||||
import 'package:dafl_project_flutter/main.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:crypto/crypto.dart';
|
||||
import 'dart:developer' as dev;
|
||||
import '../exceptions/api_exception.dart';
|
||||
|
||||
class Api {
|
||||
//from dashboard
|
||||
final _clientId = '7ceb49d874b9404492246027e4d68cf8';
|
||||
final _clientSecret = '98f9cb960bf54ebbb9ad306e7ff919cb';
|
||||
|
||||
//for web api
|
||||
get redirectUri => 'https://daflmusic.000webhostapp.com/callback/';
|
||||
final _scopes =
|
||||
'user-read-playback-state user-read-currently-playing user-read-recently-played playlist-modify-public ugc-image-upload user-modify-playback-state';
|
||||
late String _state;
|
||||
dynamic _codeVerifier;
|
||||
dynamic _codeChallenge;
|
||||
late String _encodedLogs;
|
||||
final _tokenType = 'Bearer ';
|
||||
late http.Response _response; //use _setResponse() as kind of a private setter
|
||||
final _playlistName = "Dafl's discovery";
|
||||
|
||||
//from web api
|
||||
String? _code;
|
||||
int? _expiresIn;
|
||||
String? _refreshToken;
|
||||
String? _accessToken; //use _getAccessToken() as kind of a private getter
|
||||
|
||||
//other
|
||||
final _client = http.Client();
|
||||
late Uri _urlAuthorize;
|
||||
|
||||
get urlAuthorize => _urlAuthorize;
|
||||
DateTime? _tokenEnd;
|
||||
|
||||
Api() {
|
||||
_state = _generateRandomString(16);
|
||||
_codeVerifier = _generateRandomString(_generateRandomInt(43, 128));
|
||||
_codeChallenge = _generateCodeChallenge();
|
||||
_encodedLogs = base64.encode(utf8.encode("$_clientId:$_clientSecret"));
|
||||
_urlAuthorize = Uri.https('accounts.spotify.com', 'authorize', {
|
||||
'client_id': _clientId,
|
||||
'response_type': 'code',
|
||||
'redirect_uri': redirectUri,
|
||||
'state': _state,
|
||||
'scope': _scopes,
|
||||
'show_dialog': 'false',
|
||||
'code_challenge_method': 'S256',
|
||||
'code_challenge': _codeChallenge
|
||||
});
|
||||
}
|
||||
|
||||
//PKCE generations
|
||||
|
||||
_generateRandomInt(int min, int max) {
|
||||
return min + Random().nextInt(max - min);
|
||||
}
|
||||
|
||||
_generateRandomString(int length) {
|
||||
const chars =
|
||||
'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890';
|
||||
return String.fromCharCodes(Iterable.generate(
|
||||
length, (_) => chars.codeUnitAt(Random().nextInt(chars.length))));
|
||||
}
|
||||
|
||||
_generateCodeChallenge() {
|
||||
return base64Encode(sha256.convert(utf8.encode(_codeVerifier)).bytes)
|
||||
.replaceAll('+', '-')
|
||||
.replaceAll('/', '_')
|
||||
.replaceAll('=', '');
|
||||
}
|
||||
|
||||
//session management
|
||||
|
||||
requestUserAuthorization(Uri url) async {
|
||||
if (url.queryParameters['state'] != _state.toString()) {
|
||||
throw ApiException('state');
|
||||
}
|
||||
_code = url.queryParameters['code'];
|
||||
await _requestAccessToken();
|
||||
}
|
||||
|
||||
_requestAccessToken() async {
|
||||
var urlToken = Uri.https('accounts.spotify.com', 'api/token', {
|
||||
'code': _code,
|
||||
'redirect_uri': redirectUri,
|
||||
'grant_type': 'authorization_code',
|
||||
'client_id': _clientId,
|
||||
'code_verifier': _codeVerifier
|
||||
});
|
||||
_setResponse(await _client.post(urlToken, headers: <String, String>{
|
||||
'Authorization': 'Basic $_encodedLogs',
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
}));
|
||||
var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map;
|
||||
_accessToken = decodedResponse['access_token'];
|
||||
_expiresIn = decodedResponse['expires_in'];
|
||||
_tokenEnd = DateTime.now().add(Duration(seconds: _expiresIn!));
|
||||
_refreshToken = decodedResponse['refresh_token'];
|
||||
}
|
||||
|
||||
Future<String?> _getAccessToken() async {
|
||||
if (DateTime.now().isAfter(_tokenEnd!)) {
|
||||
await _getRefreshedAccessToken();
|
||||
}
|
||||
return _accessToken;
|
||||
}
|
||||
|
||||
_setResponse(value) {
|
||||
int sc = value.statusCode;
|
||||
if (sc >= 300) {
|
||||
dev.log(value.body.toString());
|
||||
throw ApiException(sc);
|
||||
}
|
||||
_response = value;
|
||||
}
|
||||
|
||||
_getRefreshedAccessToken() async {
|
||||
var urlToken = Uri.https('accounts.spotify.com', 'api/token', {
|
||||
'grant_type': 'refresh_token',
|
||||
'refresh_token': _refreshToken,
|
||||
'client_id': _clientId
|
||||
});
|
||||
_setResponse(await _client.post(urlToken, headers: <String, String>{
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
}));
|
||||
var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map;
|
||||
_accessToken = decodedResponse['access_token'];
|
||||
_expiresIn = decodedResponse['expires_in'];
|
||||
_tokenEnd = DateTime.now().add(Duration(seconds: _expiresIn!));
|
||||
}
|
||||
|
||||
//functional methods
|
||||
|
||||
Future<String> getCurrentlyPlayingTrack() async {
|
||||
var url = Uri.https('api.spotify.com', 'v1/me/player/currently-playing');
|
||||
var token = await _getAccessToken();
|
||||
var response = await _client.get(url, headers: <String, String>{
|
||||
'Authorization': '$_tokenType $token',
|
||||
'Content-Type': 'application/json'
|
||||
});
|
||||
if (response.statusCode == 204) {
|
||||
return _getRecentlyPlayedTrack();
|
||||
}
|
||||
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
|
||||
return decodedResponse['item']['id'];
|
||||
}
|
||||
|
||||
Future<String> _getRecentlyPlayedTrack() async {
|
||||
var url = Uri.https(
|
||||
'api.spotify.com', 'v1/me/player/recently-played', {'limit': '1'});
|
||||
var token = await _getAccessToken();
|
||||
_setResponse(await _client.get(url, headers: <String, String>{
|
||||
'Authorization': '$_tokenType $token',
|
||||
'Content-Type': 'application/json'
|
||||
}));
|
||||
var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map;
|
||||
return decodedResponse['items'][0]['track']['id'];
|
||||
}
|
||||
|
||||
Future<Map> getTrackInfo(String id) async {
|
||||
var url = Uri.https('api.spotify.com', 'v1/tracks/$id');
|
||||
var token = await _getAccessToken();
|
||||
_setResponse(await _client.get(url, headers: <String, String>{
|
||||
'Authorization': '$_tokenType $token',
|
||||
'Content-Type': 'application/json'
|
||||
}));
|
||||
var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map;
|
||||
Map<String, String> info = {
|
||||
'artist': decodedResponse['artists'][0]['name'],
|
||||
'name': decodedResponse['name'],
|
||||
'cover': decodedResponse['album']['images'][0]['url']
|
||||
};
|
||||
return info;
|
||||
}
|
||||
|
||||
Future<bool> _isInPlaylist(String idTrack, String idPlaylist) async {
|
||||
var url = Uri.https('api.spotify.com', 'v1/playlists/$idPlaylist/tracks',
|
||||
{'limit': '50', 'fields': 'items(track(id))'});
|
||||
var token = await _getAccessToken();
|
||||
_setResponse(await _client.get(url, headers: <String, String>{
|
||||
'Authorization': '$_tokenType $token',
|
||||
'Content-Type': 'application/json'
|
||||
}));
|
||||
var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map;
|
||||
var res = decodedResponse['items']
|
||||
.where((element) => element['track']['id'] == idTrack)
|
||||
.toList();
|
||||
if (res.length >= 1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
addToPLaylist(String idTrack) async {
|
||||
var idPlaylist = await _getPlaylist();
|
||||
if (idPlaylist == null) {
|
||||
idPlaylist = await _createPlaylist();
|
||||
} else {
|
||||
if (await _isInPlaylist(idTrack, idPlaylist)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
var token = await _getAccessToken();
|
||||
var url = Uri.https('api.spotify.com', 'v1/playlists/$idPlaylist/tracks',
|
||||
{'uris': 'spotify:track:$idTrack'});
|
||||
_setResponse(await _client.post(url, headers: <String, String>{
|
||||
'Authorization': '$_tokenType $token',
|
||||
'Content-Type': 'application/json'
|
||||
}));
|
||||
}
|
||||
|
||||
Future<String?> _getPlaylist() async {
|
||||
var url = Uri.https('api.spotify.com', 'v1/me/playlists', {'limit': '50'});
|
||||
var token = await _getAccessToken();
|
||||
_setResponse(await _client.get(url, headers: <String, String>{
|
||||
'Authorization': '$_tokenType $token',
|
||||
'Content-Type': 'application/json'
|
||||
}));
|
||||
var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map;
|
||||
var daflplaylist = decodedResponse['items']
|
||||
.where((element) => element['name'] == _playlistName)
|
||||
.toList();
|
||||
if (daflplaylist.length == 1) {
|
||||
return daflplaylist[0]['uri'].substring(
|
||||
17); //17 char because format is 'spotify:playlist:MYPLAYLISTID'
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<String> _createPlaylist() async {
|
||||
var idUser = await MyApp.controller.currentUser.getIdSpotify();
|
||||
var token = await _getAccessToken();
|
||||
var url = Uri.https('api.spotify.com', 'v1/users/$idUser/playlists');
|
||||
_setResponse(await _client.post(url,
|
||||
headers: <String, String>{
|
||||
'Accept': 'application/json',
|
||||
'Authorization': '$_tokenType $token',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: jsonEncode(<String, String>{
|
||||
'name': _playlistName,
|
||||
'description':
|
||||
'Retrouvez toutes vos découvertes faites sur DaflMusic 🎵',
|
||||
'public': 'true'
|
||||
})));
|
||||
var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map;
|
||||
var idPlaylist = decodedResponse['id'];
|
||||
return idPlaylist;
|
||||
}
|
||||
|
||||
playTrack(String idTrack) async {
|
||||
var token = await _getAccessToken();
|
||||
var url = Uri.https('api.spotify.com', 'v1/me/player/play');
|
||||
_setResponse(await _client.put(url,
|
||||
headers: <String, String>{
|
||||
'Authorization': '$_tokenType $token',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: jsonEncode(<String, List>{
|
||||
'uris': ['spotify:track:$idTrack']
|
||||
})));
|
||||
}
|
||||
|
||||
removeFromPlaylist(String idTrack) async {
|
||||
var idPlaylist = await _getPlaylist();
|
||||
if (idPlaylist != null) {
|
||||
if (await _isInPlaylist(idTrack, idPlaylist)) {
|
||||
var token = await _getAccessToken();
|
||||
var url =
|
||||
Uri.https('api.spotify.com', 'v1/playlists/$idPlaylist/tracks');
|
||||
var jsonVar = jsonEncode(<String, List>{
|
||||
'tracks': [
|
||||
{'uri': 'spotify:track:$idTrack'}
|
||||
]
|
||||
});
|
||||
_setResponse(await _client.delete(url,
|
||||
headers: <String, String>{
|
||||
'Authorization': '$_tokenType $token',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: jsonVar));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> getIdUser() async {
|
||||
var url = Uri.https('api.spotify.com', 'v1/me');
|
||||
var token = await _getAccessToken();
|
||||
_setResponse(await _client.get(url, headers: <String, String>{
|
||||
'Authorization': '$_tokenType $token',
|
||||
'Content-Type': 'application/json'
|
||||
}));
|
||||
var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map;
|
||||
return decodedResponse['id'];
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
import 'dart:collection';
|
||||
|
||||
import '../model/music.dart';
|
||||
import '../model/spot.dart';
|
||||
|
||||
class LiveData {
|
||||
bool discoveriesSortChoice = true;
|
||||
late LinkedHashMap<Music, DateTime> discoveries;
|
||||
late List<Spot> spots;
|
||||
late Music userCurrentMusic;
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
import 'dart:developer' as dev;
|
||||
|
||||
class ApiException implements Exception {
|
||||
final String mess = 'Api exception raised,';
|
||||
|
||||
ApiException(dynamic code) {
|
||||
if (code.runtimeType == String) {
|
||||
dev.log('$mess state verification failed.');
|
||||
} else {
|
||||
dev.log('$mess status code : $code.');
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
import 'dart:developer' as dev;
|
||||
|
||||
class ApiStateException implements Exception {
|
||||
ApiStateException() {
|
||||
dev.log('State verification failed.');
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
import 'dart:developer' as dev;
|
||||
import 'package:http/http.dart';
|
||||
|
||||
class HttpException implements Exception {
|
||||
HttpException(var value) {
|
||||
dev.log('Http request failed');
|
||||
if (value.runtimeType == Response) {
|
||||
dev.log('Status code : ${value.statusCode.toString()}');
|
||||
dev.log('Body : ${value.body.toString()}');
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
import 'user.dart';
|
||||
|
||||
class Message {
|
||||
User sender;
|
||||
String senderId;
|
||||
String content;
|
||||
|
||||
Message(this.sender, this.content);
|
||||
Message(this.senderId, this.content);
|
||||
}
|
||||
|
@ -1,74 +1,8 @@
|
||||
import 'dart:async';
|
||||
import '../../../position/location.dart';
|
||||
import '../exceptions/api_exception.dart';
|
||||
import '../main.dart';
|
||||
import 'music.dart';
|
||||
import 'spot.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
class User {
|
||||
Timer? timer;
|
||||
int test = 0;
|
||||
|
||||
//attributes from DAFL
|
||||
late int idDafl;
|
||||
late String usernameDafl;
|
||||
late String passwDafl;
|
||||
List<Music> discovery = [];
|
||||
List<Spot> spots = [];
|
||||
|
||||
//attributes with Spotify API
|
||||
String? _idSpotify; //use _getIdUser() as kind of a private getter
|
||||
late Music _currentMusic;
|
||||
bool sortChoise = true;
|
||||
String idDafl;
|
||||
late String idSpotify;
|
||||
|
||||
//constructors
|
||||
User(this.usernameDafl, this.passwDafl) {
|
||||
actualiseCurrentMusic();
|
||||
}
|
||||
|
||||
Music get currentMusic => _currentMusic; //lists
|
||||
|
||||
Future<String> getIdSpotify() async {
|
||||
_idSpotify ??= await MyApp.api.getIdUser();
|
||||
return _idSpotify!;
|
||||
}
|
||||
|
||||
addDiscovery(Music music) {
|
||||
discovery.add(music);
|
||||
}
|
||||
|
||||
actualiseCurrentMusic() async {
|
||||
try {
|
||||
_currentMusic = Music(await MyApp.api.getCurrentlyPlayingTrack());
|
||||
} on ApiException {
|
||||
// TODO : add notification to show that an error occurred
|
||||
}
|
||||
}
|
||||
|
||||
listSpots() {
|
||||
print('ajout test');
|
||||
Future<String> rep = Location.sendCurrentLocation();
|
||||
//ex : dorian-2d2s52a15d2a5,audric-2x5s2az3d1s5wx5s1,lucas-s2a5d25a2a25d
|
||||
|
||||
rep.then((String result) {
|
||||
List<String> tab = result.split(",");
|
||||
//ex : [dorian-2d2s52a15d2a5 , audric-2x5s2az3d1s5wx5s1 , lucas-s2a5d25a2a25d]
|
||||
|
||||
for (var element in tab) {
|
||||
List<String> tab2 = element.split("-");
|
||||
spots.add(Spot(tab2[0], Music(tab2[1])));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getListSpots() {
|
||||
if (test == 0) {
|
||||
test = 1;
|
||||
listSpots();
|
||||
} else {
|
||||
timer =
|
||||
Timer.periodic(const Duration(seconds: 72), (Timer t) => listSpots());
|
||||
}
|
||||
}
|
||||
User(this.idDafl);
|
||||
}
|
||||
|
@ -1,6 +0,0 @@
|
||||
import 'dart:async';
|
||||
import '../model/user.dart';
|
||||
|
||||
abstract class Loader {
|
||||
Future<User> load(String username, String password);
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
import '../model/user.dart';
|
||||
|
||||
abstract class Saver{
|
||||
void save(User userToSave);
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
abstract class Searcher {
|
||||
Future<bool> searchUser(String? username, String? password);
|
||||
|
||||
Future<bool> searchByUsername(String? username);
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'dart:convert';
|
||||
import 'dart:async';
|
||||
import '../main.dart';
|
||||
|
||||
class Location {
|
||||
static Future<String> sendCurrentLocation() async {
|
||||
Uri uri = Uri.parse("http://89.83.53.34/phpmyadmin/dafldev/insert.php");
|
||||
LocationPermission permission;
|
||||
permission = await Geolocator.checkPermission();
|
||||
if (permission == LocationPermission.denied) {
|
||||
permission = await Geolocator.requestPermission();
|
||||
if (permission == LocationPermission.deniedForever) {
|
||||
//faire l'interface gra pour gérer ça
|
||||
return Future.error('Location Not Available');
|
||||
}
|
||||
}
|
||||
String actualUser = MyApp.controller.currentUser.usernameDafl;
|
||||
String actualSong = await MyApp.api.getCurrentlyPlayingTrack();
|
||||
Position current = await Geolocator.getCurrentPosition();
|
||||
await http.post(uri, body: {
|
||||
"id": actualUser.toString(),
|
||||
"latitude": current.latitude.toString(),
|
||||
"longitude": current.longitude.toString(),
|
||||
"idMusic": actualSong.toString(),
|
||||
});
|
||||
return getData();
|
||||
}
|
||||
|
||||
static Future<String> getData() async {
|
||||
String actualUser = MyApp.controller.currentUser.usernameDafl;
|
||||
Uri uri = Uri.parse("http://89.83.53.34/phpmyadmin/dafldev/distance.php");
|
||||
http.Response response = await http.post(uri, body: {
|
||||
"id": actualUser,
|
||||
});
|
||||
var data = jsonDecode(response.body);
|
||||
return data.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
import 'package:dafl_project_flutter/services/api/api_spotify_identification.dart';
|
||||
import 'package:dafl_project_flutter/services/api/api_spotify_requests.dart';
|
||||
|
||||
class ApiSpotify {
|
||||
late ApiSpotifyIdentification _identification;
|
||||
late ApiSpotifyRequests _requests;
|
||||
|
||||
ApiSpotify() {
|
||||
_identification = ApiSpotifyIdentification();
|
||||
}
|
||||
|
||||
ApiSpotifyIdentification get identification => _identification;
|
||||
|
||||
ApiSpotifyRequests get requests => _requests;
|
||||
|
||||
apiAuthorization(url) async {
|
||||
await _identification.setCode(url);
|
||||
_requests = ApiSpotifyRequests(await _identification.createToken());
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:math';
|
||||
import '../../exceptions/api_state_exception.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:crypto/crypto.dart';
|
||||
import '../http_response_verification.dart';
|
||||
import 'token_spotify.dart';
|
||||
|
||||
class ApiSpotifyIdentification extends HttpResponseVerification {
|
||||
static const String clientId = '7ceb49d874b9404492246027e4d68cf8';
|
||||
final String _clientSecret = '98f9cb960bf54ebbb9ad306e7ff919cb';
|
||||
final String _scopes =
|
||||
'user-read-playback-state user-read-currently-playing user-read-recently-played playlist-modify-public ugc-image-upload user-modify-playback-state';
|
||||
|
||||
late String _state;
|
||||
late String _codeVerifier;
|
||||
late String _codeChallenge;
|
||||
late String _encodedLogs;
|
||||
|
||||
String? _code;
|
||||
|
||||
String get redirectUri => 'https://codefirst.iut.uca.fr/containers/apiredirect-felixmielcarek/';
|
||||
|
||||
Uri get urlAuthorize => Uri.https('accounts.spotify.com', 'authorize', {
|
||||
'client_id': clientId,
|
||||
'response_type': 'code',
|
||||
'redirect_uri': redirectUri,
|
||||
'state': _state,
|
||||
'scope': _scopes,
|
||||
'show_dialog': 'false',
|
||||
'code_challenge_method': 'S256',
|
||||
'code_challenge': _codeChallenge
|
||||
});
|
||||
|
||||
ApiSpotifyIdentification() {
|
||||
_state = _generateRandomString(16);
|
||||
_codeVerifier = _generateRandomString(_generateRandomInt(43, 128));
|
||||
_codeChallenge = _generateCodeChallenge();
|
||||
_encodedLogs = base64.encode(utf8.encode("$clientId:$_clientSecret"));
|
||||
}
|
||||
|
||||
_generateRandomInt(int min, int max) {
|
||||
return min + Random().nextInt(max - min);
|
||||
}
|
||||
|
||||
_generateRandomString(int length) {
|
||||
const chars =
|
||||
'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890';
|
||||
return String.fromCharCodes(Iterable.generate(
|
||||
length, (_) => chars.codeUnitAt(Random().nextInt(chars.length))));
|
||||
}
|
||||
|
||||
_generateCodeChallenge() {
|
||||
return base64Encode(sha256.convert(utf8.encode(_codeVerifier)).bytes)
|
||||
.replaceAll('+', '-')
|
||||
.replaceAll('/', '_')
|
||||
.replaceAll('=', '');
|
||||
}
|
||||
|
||||
setCode(Uri url) async {
|
||||
if (url.queryParameters['state'] != _state.toString()) {
|
||||
throw ApiStateException();
|
||||
}
|
||||
_code = url.queryParameters['code'];
|
||||
}
|
||||
|
||||
Future<TokenSpotify> createToken() async {
|
||||
var urlToken = Uri.https('accounts.spotify.com', 'api/token', {
|
||||
'code': _code,
|
||||
'redirect_uri': redirectUri,
|
||||
'grant_type': 'authorization_code',
|
||||
'client_id': clientId,
|
||||
'code_verifier': _codeVerifier
|
||||
});
|
||||
setResponse(await http.post(urlToken, headers: <String, String>{
|
||||
'Authorization': 'Basic $_encodedLogs',
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
}));
|
||||
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
|
||||
return TokenSpotify(decodedResponse['access_token'],
|
||||
decodedResponse['refresh_token'], decodedResponse['expires_in']);
|
||||
}
|
||||
}
|
@ -0,0 +1,184 @@
|
||||
import 'dart:collection';
|
||||
import 'dart:convert';
|
||||
import 'package:dafl_project_flutter/services/api/token_spotify.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import '../../main.dart';
|
||||
import '../http_response_verification.dart';
|
||||
|
||||
class ApiSpotifyRequests extends HttpResponseVerification {
|
||||
final String _tokenType = 'Bearer ';
|
||||
final String _playlistName = "Dafl's discovery";
|
||||
final TokenSpotify _token;
|
||||
|
||||
ApiSpotifyRequests(this._token);
|
||||
|
||||
Future<String> getCurrentlyPlayingTrack() async {
|
||||
var url = Uri.https('api.spotify.com', 'v1/me/player/currently-playing');
|
||||
var token = await _token.getAccessToken();
|
||||
var response = await http.get(url, headers: <String, String>{
|
||||
'Authorization': '$_tokenType $token',
|
||||
'Content-Type': 'application/json'
|
||||
});
|
||||
if (response.statusCode == 204) {
|
||||
return _getRecentlyPlayedTrack();
|
||||
}
|
||||
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
|
||||
return decodedResponse['item']['id'];
|
||||
}
|
||||
|
||||
Future<String> _getRecentlyPlayedTrack() async {
|
||||
var url = Uri.https(
|
||||
'api.spotify.com', 'v1/me/player/recently-played', {'limit': '1'});
|
||||
var token = await _token.getAccessToken();
|
||||
setResponse(await http.get(url, headers: <String, String>{
|
||||
'Authorization': '$_tokenType $token',
|
||||
'Content-Type': 'application/json'
|
||||
}));
|
||||
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
|
||||
return decodedResponse['items'][0]['track']['id'];
|
||||
}
|
||||
|
||||
Future<Map> getTrackInfo(String id) async {
|
||||
var url = Uri.https('api.spotify.com', 'v1/tracks/$id');
|
||||
var token = await _token.getAccessToken();
|
||||
setResponse(await http.get(url, headers: <String, String>{
|
||||
'Authorization': '$_tokenType $token',
|
||||
'Content-Type': 'application/json'
|
||||
}));
|
||||
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
|
||||
Map<String, String> infos = {
|
||||
'artist': decodedResponse['artists'][0]['name'],
|
||||
'name': decodedResponse['name'],
|
||||
'cover': decodedResponse['album']['images'][0]['url']
|
||||
};
|
||||
return infos;
|
||||
}
|
||||
|
||||
Future<String> getIdUser() async {
|
||||
var url = Uri.https('api.spotify.com', 'v1/me');
|
||||
var token = await _token.getAccessToken();
|
||||
setResponse(await http.get(url, headers: <String, String>{
|
||||
'Authorization': '$_tokenType $token',
|
||||
'Content-Type': 'application/json'
|
||||
}));
|
||||
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
|
||||
return decodedResponse['id'];
|
||||
}
|
||||
|
||||
playTrack(String idTrack) async {
|
||||
var token = await _token.getAccessToken();
|
||||
var url = Uri.https('api.spotify.com', 'v1/me/player/play');
|
||||
setResponse(await http.put(url,
|
||||
headers: <String, String>{
|
||||
'Authorization': '$_tokenType $token',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: jsonEncode(<String, List>{
|
||||
'uris': ['spotify:track:$idTrack']
|
||||
})));
|
||||
}
|
||||
|
||||
Future<String> _getPlaylistId() async {
|
||||
var url = Uri.https('api.spotify.com', 'v1/me/playlists', {'limit': '50'});
|
||||
var token = await _token.getAccessToken();
|
||||
setResponse(await http.get(url, headers: <String, String>{
|
||||
'Authorization': '$_tokenType $token',
|
||||
'Content-Type': 'application/json'
|
||||
}));
|
||||
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
|
||||
var daflPlaylist = decodedResponse['items']
|
||||
.where((element) => element['name'] == _playlistName)
|
||||
.toList();
|
||||
if (daflPlaylist.length == 1) {
|
||||
return daflPlaylist[0]['uri'].substring(
|
||||
17); //17 char because format is 'spotify:playlist:MYPLAYLISTID'
|
||||
}
|
||||
return await _createPlaylist();
|
||||
}
|
||||
|
||||
Future<String> _createPlaylist() async {
|
||||
var idUser = MyApp.controller.getIdSpotify();
|
||||
var token = await _token.getAccessToken();
|
||||
var url = Uri.https('api.spotify.com', 'v1/users/$idUser/playlists');
|
||||
setResponse(await http.post(url,
|
||||
headers: <String, String>{
|
||||
'Accept': 'application/json',
|
||||
'Authorization': '$_tokenType $token',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: jsonEncode(<String, String>{
|
||||
'name': _playlistName,
|
||||
'description':
|
||||
'Retrouvez toutes vos découvertes faites sur DaflMusic 🎵',
|
||||
'public': 'true'
|
||||
})));
|
||||
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
|
||||
var idPlaylist = decodedResponse['id'];
|
||||
return idPlaylist;
|
||||
}
|
||||
|
||||
addToPlaylist(String idTrack) async {
|
||||
var idPlaylist = await _getPlaylistId();
|
||||
if (await _isInPlaylist(idTrack, idPlaylist)) {
|
||||
return;
|
||||
}
|
||||
var token = await _token.getAccessToken();
|
||||
var url = Uri.https('api.spotify.com', 'v1/playlists/$idPlaylist/tracks',
|
||||
{'uris': 'spotify:track:$idTrack'});
|
||||
setResponse(await http.post(url, headers: <String, String>{
|
||||
'Authorization': '$_tokenType $token',
|
||||
'Content-Type': 'application/json'
|
||||
}));
|
||||
}
|
||||
|
||||
Future<bool> _isInPlaylist(String idTrack, String idPlaylist) async {
|
||||
var url = Uri.https('api.spotify.com', 'v1/playlists/$idPlaylist/tracks',
|
||||
{'limit': '50', 'fields': 'items(track(id))'});
|
||||
var token = await _token.getAccessToken();
|
||||
setResponse(await http.get(url, headers: <String, String>{
|
||||
'Authorization': '$_tokenType $token',
|
||||
'Content-Type': 'application/json'
|
||||
}));
|
||||
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
|
||||
var res = decodedResponse['items']
|
||||
.where((element) => element['track']['id'] == idTrack)
|
||||
.toList();
|
||||
return (res.length >= 1) ? true : false;
|
||||
}
|
||||
|
||||
removeFromPlaylist(String idTrack) async {
|
||||
var idPlaylist = await _getPlaylistId();
|
||||
if (await _isInPlaylist(idTrack, idPlaylist)) {
|
||||
var token = await _token.getAccessToken();
|
||||
var url = Uri.https('api.spotify.com', 'v1/playlists/$idPlaylist/tracks');
|
||||
var jsonVar = jsonEncode(<String, List>{
|
||||
'tracks': [
|
||||
{'uri': 'spotify:track:$idTrack'}
|
||||
]
|
||||
});
|
||||
setResponse(await http.delete(url,
|
||||
headers: <String, String>{
|
||||
'Authorization': '$_tokenType $token',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: jsonVar));
|
||||
}
|
||||
}
|
||||
|
||||
Future<LinkedHashMap<String, DateTime>> getPlaylistTracks() async {
|
||||
var idPlaylist = await _getPlaylistId();
|
||||
var url = Uri.https('api.spotify.com', 'v1/playlists/$idPlaylist/tracks',
|
||||
{'fields': 'items(track(id),added_at)'});
|
||||
var token = await _token.getAccessToken();
|
||||
setResponse(await http.get(url, headers: <String, String>{
|
||||
'Authorization': '$_tokenType $token',
|
||||
'Content-Type': 'application/json'
|
||||
}));
|
||||
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
|
||||
LinkedHashMap<String, DateTime> mapRes = LinkedHashMap();
|
||||
decodedResponse['items'].toList().forEach((elem) =>
|
||||
{mapRes[elem['track']['id']] = DateTime.parse(elem['added_at'])});
|
||||
return mapRes;
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:dafl_project_flutter/services/api/api_spotify_identification.dart';
|
||||
|
||||
import '../http_response_verification.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
class TokenSpotify extends HttpResponseVerification {
|
||||
String _accessToken;
|
||||
final String _refreshToken;
|
||||
late DateTime _tokenEnd;
|
||||
|
||||
TokenSpotify(this._accessToken, this._refreshToken, int expiresIn) {
|
||||
_setTokenEnd(expiresIn);
|
||||
}
|
||||
|
||||
_setTokenEnd(int expiresIn) {
|
||||
_tokenEnd = DateTime.now().add(Duration(seconds: expiresIn));
|
||||
}
|
||||
|
||||
Future<String> getAccessToken() async {
|
||||
if (DateTime.now().isAfter(_tokenEnd)) {
|
||||
await _actualiseToken();
|
||||
}
|
||||
return _accessToken;
|
||||
}
|
||||
|
||||
_actualiseToken() async {
|
||||
var urlToken = Uri.https('accounts.spotify.com', 'api/token', {
|
||||
'grant_type': 'refresh_token',
|
||||
'refresh_token': _refreshToken,
|
||||
'client_id': ApiSpotifyIdentification.clientId
|
||||
});
|
||||
setResponse(await http.post(urlToken, headers: <String, String>{
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
}));
|
||||
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
|
||||
_accessToken = decodedResponse['access_token'];
|
||||
_setTokenEnd(decodedResponse['expires_in']);
|
||||
}
|
||||
}
|
@ -1,26 +1,25 @@
|
||||
import 'dart:async';
|
||||
import 'loader.dart';
|
||||
import '../model/user.dart';
|
||||
import '../../model/user.dart';
|
||||
import 'database_connexion.dart';
|
||||
import 'dart:developer' as dev;
|
||||
|
||||
class DatabaseLoader extends Loader {
|
||||
class DatabaseLoader implements Loader {
|
||||
// Load an user from database
|
||||
@override
|
||||
Future<User> load(String username, String password) async {
|
||||
Future<User?> load(String username, String password) async {
|
||||
final connection = await DatabaseConnexion.initConnexion();
|
||||
|
||||
var queryResult = await connection
|
||||
.query(
|
||||
'select * from utilisateur where username = @username AND password = @password',
|
||||
'select username from utilisateur where username = @username AND password = @password',
|
||||
{'username': username, 'password': password})
|
||||
.toList()
|
||||
.then((result) {
|
||||
dev.log(result.toString());
|
||||
if (result.isNotEmpty) {
|
||||
return User(username, password);
|
||||
return User(username);
|
||||
} else {
|
||||
return User("", "");
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.whenComplete(() {
|
@ -1,20 +1,15 @@
|
||||
import 'database_connexion.dart';
|
||||
import 'saver.dart';
|
||||
import '../model/user.dart';
|
||||
|
||||
class DatabaseSaver extends Saver {
|
||||
class DatabaseSaver implements Saver {
|
||||
// Save user in the database
|
||||
@override
|
||||
void save(User userToSave) async {
|
||||
void save(String idDafl, String passw) async {
|
||||
final connection = await DatabaseConnexion.initConnexion();
|
||||
|
||||
connection.execute(
|
||||
'insert into utilisateur (username, password) values (@username, @password)',
|
||||
{
|
||||
'id': '',
|
||||
'username': userToSave.usernameDafl,
|
||||
'password': userToSave.passwDafl
|
||||
}).whenComplete(() {
|
||||
{'id': '', 'username': idDafl, 'password': passw}).whenComplete(() {
|
||||
connection.close();
|
||||
});
|
||||
}
|
@ -1,15 +1,12 @@
|
||||
import 'database_connexion.dart';
|
||||
import 'searcher.dart';
|
||||
|
||||
class DatabaseSearcher extends Searcher {
|
||||
@override
|
||||
Future<bool> searchUser(String? username, String? password) async {
|
||||
return true;
|
||||
}
|
||||
class DatabaseSearcher implements Searcher {
|
||||
|
||||
|
||||
// Search an user in the database by username
|
||||
@override
|
||||
Future<bool> searchByUsername(String? username) async {
|
||||
Future<bool> searchUser(String? username) async {
|
||||
final connection = await DatabaseConnexion.initConnexion();
|
||||
|
||||
bool queryResult = await connection
|
@ -0,0 +1,37 @@
|
||||
import 'package:dafl_project_flutter/services/database/database_loader.dart';
|
||||
import 'package:dafl_project_flutter/services/database/database_user_modifier.dart';
|
||||
import 'package:dafl_project_flutter/services/database/database_saver.dart';
|
||||
import 'package:dafl_project_flutter/services/database/database_searcher.dart';
|
||||
import 'package:dafl_project_flutter/services/database/loader.dart';
|
||||
import 'package:dafl_project_flutter/services/database/user_modifier.dart';
|
||||
import 'package:dafl_project_flutter/services/database/saver.dart';
|
||||
import 'package:dafl_project_flutter/services/database/searcher.dart';
|
||||
|
||||
import '../../model/user.dart';
|
||||
|
||||
class DataBaseService {
|
||||
static final Loader _loader = DatabaseLoader();
|
||||
static final Searcher _searcher = DatabaseSearcher();
|
||||
static final Saver _saver = DatabaseSaver();
|
||||
static final UserModifier _userModifier = DatabaseUserModifier();
|
||||
|
||||
void save(String idDafl, String passw) {
|
||||
_saver.save(idDafl, passw);
|
||||
}
|
||||
|
||||
Future<User?> load(String username, String password) async {
|
||||
return _loader.load(username, password);
|
||||
}
|
||||
|
||||
Future<bool> searchUser(String username) async {
|
||||
return await _searcher.searchUser(username);
|
||||
}
|
||||
|
||||
changeUsername(String newName) {
|
||||
//TODO : call database method
|
||||
}
|
||||
|
||||
changeCurrentPassword(String newPass) {
|
||||
//TODO : call database method
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
import 'package:dafl_project_flutter/services/database/user_modifier.dart';
|
||||
|
||||
class DatabaseUserModifier implements UserModifier {
|
||||
@override
|
||||
changeCurrentPassword(String userToModify, String newPass) {
|
||||
// TODO: implement changeCurrentPassword
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
changeUsername(String userToModify, String newName) {
|
||||
// TODO: implement changeUsername
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
import 'dart:async';
|
||||
import '../../model/user.dart';
|
||||
|
||||
abstract class Loader {
|
||||
Future<User?> load(String username, String password);
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
abstract class Saver {
|
||||
void save(String idDafl, String passw);
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
abstract class Searcher {
|
||||
Future<bool> searchUser(String? username);
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
|
||||
|
||||
|
||||
import 'package:dafl_project_flutter/model/user.dart';
|
||||
|
||||
abstract class UserModifier{
|
||||
changeUsername(String userToModify, String newName);
|
||||
|
||||
changeCurrentPassword(String userToModify, String newPass);
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
import '../exceptions/http_exception.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
abstract class HttpResponseVerification {
|
||||
@protected
|
||||
late http.Response response;
|
||||
|
||||
@protected
|
||||
setResponse(var value) {
|
||||
if (value.statusCode >= 300) {
|
||||
throw HttpException(value);
|
||||
}
|
||||
response = value;
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
import 'package:dafl_project_flutter/model/spot.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'dart:convert';
|
||||
import 'dart:async';
|
||||
import '../../main.dart';
|
||||
|
||||
class Location {
|
||||
static Future<List<Spot>> sendCurrentLocation() async {
|
||||
Uri uri = Uri.parse(
|
||||
"https://codefirst.iut.uca.fr/containers/php_script-dorianhodin/insertAndMakeListUser.php");
|
||||
LocationPermission permission = await Geolocator.checkPermission();
|
||||
|
||||
if (permission == LocationPermission.denied) {
|
||||
permission = await Geolocator.requestPermission();
|
||||
|
||||
if (permission == LocationPermission.deniedForever) {
|
||||
//TODO : handle this case
|
||||
}
|
||||
}
|
||||
|
||||
String actualUser = MyApp.controller.getIdDafl();
|
||||
String actualSong = MyApp.controller.getCurrentMusic().id;
|
||||
Position current = await Geolocator.getCurrentPosition();
|
||||
|
||||
http.Response response = await http.post(uri, body: {
|
||||
"id": actualUser,
|
||||
"latitude": current.latitude.toString(),
|
||||
"longitude": current.longitude.toString(),
|
||||
"idMusic": actualSong,
|
||||
});
|
||||
|
||||
var data = jsonDecode(response.body);
|
||||
Map<String, String> spotsData = {};
|
||||
List<Spot> spots = [];
|
||||
|
||||
if (data == 2) {
|
||||
return Future.error("Failed to connect, connection timeout");
|
||||
} else if (data == 3) {
|
||||
return Future.error("POST method failed");
|
||||
} else {
|
||||
data.forEach((s) => spotsData.putIfAbsent(s['user'], () => s['music']));
|
||||
}
|
||||
|
||||
spotsData.forEach((key, value) async {
|
||||
spots.add(Spot(key, await MyApp.controller.getCompleteMusic(value)));
|
||||
});
|
||||
return spots;
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
DROP TABLE IF EXISTS Musique;
|
||||
DROP TABLE IF EXISTS Matchs;
|
||||
DROP TABLE IF EXISTS LikeDafl;
|
||||
DROP TABLE IF EXISTS UserDafl;
|
||||
|
||||
|
||||
CREATE TABLE UserDafl(
|
||||
idDafl INT PRIMARY KEY,
|
||||
pseudo varchar(50) NOT NULL,
|
||||
idSpotify varchar(150) NOT NULL,
|
||||
profilPicture varchar(200) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE Musique(
|
||||
idUser INT REFERENCES UserDafl(idDafl),
|
||||
idMusic INT,
|
||||
title varchar(50) NOT NULL,
|
||||
artist varchar(50) NOT NULL,
|
||||
album varchar(50) NOT NULL,
|
||||
category varchar(100),
|
||||
PRIMARY KEY(idUser,idMusic)
|
||||
);
|
||||
|
||||
CREATE TABLE Matchs(
|
||||
idUserA INT REFERENCES UserDafl(idDafl),
|
||||
idUserB INT REFERENCES UserDafl(idDafl),
|
||||
dateMatch date NOT NULL,
|
||||
PRIMARY KEY(idUserA,idUserB)
|
||||
);
|
||||
|
||||
CREATE TABLE LikeDafl(
|
||||
idUserWhoLike INT REFERENCES UserDafl(idDafl),
|
||||
idUserWhoGetLike INT REFERENCES UserDafl(idDafl),
|
||||
dateLike date NOT NULL,
|
||||
PRIMARY KEY(idUserWhoLike,idUserWhoGetLike)
|
||||
);
|
||||
|
||||
CREATE TABLE MessageDafl(
|
||||
senderID INT NOT NULL REFERENCES UserDafl(idDafl) ,
|
||||
idMessage INT PRIMARY KEY,
|
||||
content varchar(500),
|
||||
dateMess date NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE ConversationDafl(
|
||||
idUserA INT NOT NULL REFERENCES UserDafl(idDafl),
|
||||
idUserB INT NOT NULL REFERENCES UserDafl(idDafl),
|
||||
idConversation INT PRIMARY KEY,
|
||||
waiting BOOLEAN NOT NULL CHECK (waiting=1 OR waiting=0)
|
||||
);
|
||||
|
||||
CREATE TABLE MessToConv(
|
||||
idConv INT REFERENCES Conversation(idConversation),
|
||||
idMsg INT REFERENCES Message(idMessage),
|
||||
PRIMARY KEY (idConv,idMsg)
|
||||
);
|
@ -0,0 +1,4 @@
|
||||
FROM php:8.1-apache
|
||||
RUN apt-get update && apt-get upgrade -y
|
||||
RUN docker-php-ext-install mysqli
|
||||
COPY ./script /var/www/html
|
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
function connection(): bool|int|mysqli
|
||||
{
|
||||
|
||||
$username = $_ENV["USER"]; //Get the username
|
||||
$host = $_ENV["HOST"]; //Get the url of the database
|
||||
$password = $_ENV["PASSWORD"]; //Get the password for the user selected
|
||||
$db_name = $_ENV["DATABASE"]; //Get the name of the database
|
||||
|
||||
try { //Try to connect to the database
|
||||
|
||||
return mysqli_connect($host, $username, $password,$db_name); //Connecting to database
|
||||
|
||||
}catch (mysqli_sql_exception) { //If the connection failed
|
||||
|
||||
return -1; //Send a return code as -1, so insertAndMakeListUser.php can know if the connection is successful
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
function metersBetweenTwoUser($lat1, $lng1, $lat2, $lng2): float
|
||||
{
|
||||
$earth_radius = 6378137; // Radius of the Earth in meters :
|
||||
|
||||
$rlo1 = deg2rad($lng1); //Transform the coordinate longitude1 from degree to radian
|
||||
$rla1 = deg2rad($lat1); //Transform the coordinate latitude1 from degree to radian
|
||||
$rlo2 = deg2rad($lng2); //Transform the coordinate longitude2 from degree to radian
|
||||
$rla2 = deg2rad($lat2); //Transform the coordinate latitude2 from degree to radian
|
||||
|
||||
$dlo = ($rlo2 - $rlo1) / 2; //Stock in $dlo the result of the calcul : ($rlo2 - $rlo1) / 2
|
||||
$dla = ($rla2 - $rla1) / 2; //Stock in $dla the result of the calcul : ($rla2 - $rla1) / 2
|
||||
|
||||
$a = (sin($dla) * sin($dla)) + cos($rla1) * cos($rla2) * (sin($dlo) * sin($dlo)); //Do some operations to return the distance in meters
|
||||
|
||||
$d = 2 * atan2(sqrt($a), sqrt(1 - $a)); //Do some operations to return the distance in meters
|
||||
|
||||
return round($earth_radius * $d); // Return the distance in meters between 2 GPS points
|
||||
}
|
||||
|
||||
function insertUserAndReturnList(): array|int
|
||||
{
|
||||
|
||||
include "config.php";
|
||||
$res = connection();
|
||||
|
||||
if (strcmp(gettype($res),"integer")==0) {
|
||||
return 2;
|
||||
}
|
||||
$query = "CREATE TABLE IF NOT EXISTS gps (
|
||||
id varchar(30) PRIMARY KEY,
|
||||
latitude double NOT NULL,
|
||||
longitude double NOT NULL,
|
||||
idMusic varchar(100) NOT NULL,
|
||||
dateLog date NOT NULL
|
||||
);";
|
||||
mysqli_query($res, $query);
|
||||
|
||||
if (!empty($_POST)) { //Check if the method POST return something
|
||||
|
||||
$id = $_POST['id']; //Get the result of POST method
|
||||
$latitude = $_POST['latitude']; //Get the result of POST method
|
||||
$longitude = $_POST['longitude']; //Get the result of POST method
|
||||
$idMusic = $_POST['idMusic']; //Get the result of POST method
|
||||
|
||||
$latitude = doubleval($latitude); //Convert a string to a double
|
||||
$longitude = doubleval($longitude); //Convert a string to a double
|
||||
|
||||
$query = "DELETE FROM gps WHERE (TIMESTAMPDIFF(MINUTE,dateLog,NOW())>10);";
|
||||
mysqli_query($res, $query);
|
||||
|
||||
$query = "SELECT id FROM gps WHERE id = '$id' ";
|
||||
$results = mysqli_query($res, $query); //Execute the SQL command
|
||||
|
||||
if (empty($results->fetch_row()[0])){
|
||||
|
||||
$query = "INSERT INTO gps(id,latitude,longitude,idMusic,dateLog) VALUES('$id','$latitude','$longitude','$idMusic',NOW());"; //Insert into the database the new data and new information about this user
|
||||
|
||||
}else{
|
||||
|
||||
$query = "UPDATE gps SET latitude='$latitude', longitude='$longitude', idMusic='$idMusic', dateLog=NOW() WHERE id='$id'"; //Delete the actual line and replace this line with the next lines
|
||||
|
||||
}
|
||||
|
||||
mysqli_query($res, $query);
|
||||
|
||||
$query = "SELECT * FROM gps WHERE id != '$id'"; //Browse all the database
|
||||
$results = mysqli_query($res, $query); //Execute the SQL command
|
||||
$listUser = []; //Set the listUser to an empty list
|
||||
|
||||
while ($row = $results->fetch_row()) { //For all the row in the database
|
||||
|
||||
$lat2 = $row[1]; //Set $lat2 to the latitude of the user who is in the actual row
|
||||
$lng2 = $row[2]; //Set $lng2 to the latitude of the user who is in the actual row
|
||||
$userID = $row[0]; //Set $userID to the username of the user who is in the actual row
|
||||
$idMusic = $row[3]; //Set $idMusic to the id of the actual song of the user who is in the actual row
|
||||
|
||||
$dist = metersBetweenTwoUser($latitude, $longitude, $lat2, $lng2); //With the function meters, determinate the distance between the current user and the user who is in the actual row
|
||||
|
||||
if ($dist <= 100) { //If the user in the actual row is less than 100 meters away of the current user
|
||||
|
||||
$listUser[] = ['user' => $userID, 'music' => $idMusic]; //Add the username and the ID of the song that user who is in the actual row is listening
|
||||
|
||||
}
|
||||
}
|
||||
return $listUser; //Return an array
|
||||
|
||||
} else { //If the method POST return nothing
|
||||
|
||||
return 3; //Return a code error
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
print(json_encode(insertUserAndReturnList()));
|
Loading…
Reference in new issue